From 012a9481ebb3a95504731ce97739daea6573dff7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=A8=F0=9F=87=B3=E9=92=9F=E6=99=BA=E5=BC=BA=20?= =?UTF-8?q?=E3=80=8E=E6=B1=9F=E8=A5=BF=E9=9D=92=E5=9E=A3=E7=A7=91=E6=8A=80?= =?UTF-8?q?=E3=80=8F?= Date: Thu, 30 Oct 2025 00:30:03 +0800 Subject: [PATCH 1/4] added the basic and necessary functions --- .../generator/android_deeplinking_qr.rb | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 modules/auxiliary/generator/android_deeplinking_qr.rb diff --git a/modules/auxiliary/generator/android_deeplinking_qr.rb b/modules/auxiliary/generator/android_deeplinking_qr.rb new file mode 100644 index 0000000000000..2433f574ff8bd --- /dev/null +++ b/modules/auxiliary/generator/android_deeplinking_qr.rb @@ -0,0 +1,33 @@ +require 'English' + +class MetasploitModule < Msf::Auxiliary + include Msf::Exploit::FILEFORMAT + + def initialize(info = {}) do + super(update_info(info, + 'Name' => 'Android Deep Link QR Code Payload Generator', + 'Description' => %q{ + This module generates QR codes containing payload URLs for Android Deep Linking. + When scanned, the QR code directs to a malicious Deep Linking. + }, + 'Author' => [ 'ctkqiang' ], + 'License' => MSF_LICENSE + )) + + register_options([ + # TODO + ]) + + @@list_of_deeplink = [ + "weixin://", + "grab://", + "boost://", + ] + + end + + def run + target_deep_link = "" + + end +end \ No newline at end of file From c95204f7ccf9724115fd021f55407a6cfc63e8b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=A8=F0=9F=87=B3=E9=92=9F=E6=99=BA=E5=BC=BA=20?= =?UTF-8?q?=E3=80=8E=E6=B1=9F=E8=A5=BF=E9=9D=92=E5=9E=A3=E7=A7=91=E6=8A=80?= =?UTF-8?q?=E3=80=8F?= Date: Fri, 31 Oct 2025 14:24:21 +0800 Subject: [PATCH 2/4] Feat: Enhance Android Deep Link QR Code Generator with expanded scheme options - Updated module usage comments for clarity and conciseness - Integrated a comprehensive list of deep link schemes into DEEPLINK_SCHEME options - Removed redundant @list_of_deeplink variable after integrating its contents into OptEnum --- .../generator/android_deeplinking_qr.rb | 237 +++++++++++++++++- 1 file changed, 226 insertions(+), 11 deletions(-) diff --git a/modules/auxiliary/generator/android_deeplinking_qr.rb b/modules/auxiliary/generator/android_deeplinking_qr.rb index 2433f574ff8bd..60abe1a39d4fc 100644 --- a/modules/auxiliary/generator/android_deeplinking_qr.rb +++ b/modules/auxiliary/generator/android_deeplinking_qr.rb @@ -1,33 +1,248 @@ -require 'English' +require 'msf/core' +require 'chunky_png' +require 'rqrcode' + class MetasploitModule < Msf::Auxiliary include Msf::Exploit::FILEFORMAT - def initialize(info = {}) do + # How to use this module: + # + # 1. Load the module: + # 2. Set the deep link scheme (like for Wechat lets say): + # `use auxiliary/generator/android_deeplinking_qr` + # + # `set DEEPLINK_SCHEME weixin://` + # + # 3. Set the deep link path : + # `set DEEPLINK_PATH dl/scanqr?type=qr ` + # + # 4. Specify the output filename for the generated QR code: + # `set FILENAME wechat_qr.png` + # + # 5. Run the module to generate the QR code: + # `run` + + def initialize(info = {}) super(update_info(info, 'Name' => 'Android Deep Link QR Code Payload Generator', 'Description' => %q{ - This module generates QR codes containing payload URLs for Android Deep Linking. - When scanned, the QR code directs to a malicious Deep Linking. + This module make QR code with ANdroid Deep Link. + When user scan QR, phone open app with deep link. + Can use for test app security or social engineering. }, 'Author' => [ 'ctkqiang' ], 'License' => MSF_LICENSE )) register_options([ - # TODO + OptEnum.new('DEEPLINK_SCHEME', [true, 'Choose deep link scheme', 'weixin://', [ + 'weixin://', + 'grab://', + 'boost://', + 'alipay://', + 'fb://', + 'instagram://', + 'twitter://', + 'line://', + 'telegram://', + 'whatsapp://', + 'tiktok://', + 'shopee://', + 'lazada://', + 'gpay://', + 'applepay://', + 'youtube://', + 'spotify://', + 'linkedin://', + 'pinterest://', + 'snapchat://', + 'paypal://', + 'skype://', + 'discord://', + 'slack://', + 'zoomus://', + 'meet://', + 'waze://', + 'maps://', + 'uber://', + 'lyft://', + 'cameraplus://', + 'vimeo://', + 'tumblr://', + 'reddit://', + 'hulu://', + 'netflix://', + 'soundcloud://', + 'deezer://', + 'tidal://', + 'messenger://', + 'fb-messenger://', + 'skype-for-business://', + 'teams://', + 'onedrive://', + 'dropbox://', + 'box://', + 'zoom://', + 'twitch://', + 'quora://', + 'medium://', + 'goodreads://', + 'yelp://', + 'tripadvisor://', + 'booking://', + 'airbnb://', + 'grabpay://', + 'wechatpay://', + 'ocbc://', + 'maybank2u://', + 'rhb://', + 'cimb://', + 'dbs://', + 'hsbc://', + 'standardchartered://', + 'custom://' + ]]), + OptString.new('CUSTOM_SCHEME', [false, 'If choose custom, put scheme here', 'myapp://']), + OptString.new('DEEPLINK_PATH', [false, 'Deep link path and parameters', 'pay?amount=100']), + OptString.new('FILENAME', [true, 'QR code output file', 'deeplink_qr.png']), + OptInt.new('SIZE', [true, 'QR code size in pixel', 400]) ]) - @@list_of_deeplink = [ - "weixin://", - "grab://", - "boost://", - ] + # List for reference + # maybe add more in future + end def run - target_deep_link = "" + scheme = datastore['DEEPLINK_SCHEME'] + + if scheme == 'custom://' + custom_scheme = datastore['CUSTOM_SCHEME'] + if custom_scheme.empty? + print_error("Please set CUSTOM_SCHEME option") + return + end + + scheme = custom_scheme + end + + path = datastore['DEEPLINK_PATH'] || "" + + if path.empty? + target_deep_link = scheme + else + if path.start_with?('/') + target_deep_link = scheme + path + else + target_deep_link = scheme + '/' + path + end + end + + print_status("Start generate QR code for deep link...") + print_status("Deep Link: #{target_deep_link}") + + app_name = get_app_name(scheme) + + print_status("This deep link will open: #{app_name}") + begin + generate_qr_code(target_deep_link) + + print_good("QR code generate success: #{datastore['FILENAME']}") + print_warning("When user scan this QR, #{app_name} will open with deep link") + + rescue => e + print_error("Generate QR code fail: #{e.message}") + if e.message.include?('missing constant') || e.message.include?('require') + print_error("Maybe need install gem: gem install rqrcode chunky_png") + end + end end + + private + + def generate_qr_code(url) + qrcode = RQRCode::QRCode.new(url) + + png = qrcode.as_png( + size: datastore['SIZE'], + border_modules: 1, + module_px_size: 6, + fill: 'white', + color: 'black' + ) + + File.binwrite(datastore['FILENAME'], png.to_s) + end + + def get_app_name(scheme) + case scheme + when 'weixin://' then 'WeChat' + when 'grab://' then 'Grab' + when 'boost://' then 'Boost' + when 'alipay://' then 'Alipay' + when 'fb://' then 'Facebook' + when 'instagram://' then 'Instagram' + when 'twitter://' then 'Twitter' + when 'line://' then 'LINE' + when 'telegram://' then 'Telegram' + when 'whatsapp://' then 'WhatsApp' + when 'tiktok://' then 'TikTok' + when 'shopee://' then 'Shopee' + when 'lazada://' then 'Lazada' + when 'gpay://' then 'Google Pay' + when 'applepay://' then 'Apple Pay' + when 'youtube://' then 'YouTube' + when 'spotify://' then 'Spotify' + when 'linkedin://' then 'LinkedIn' + when 'pinterest://' then 'Pinterest' + when 'snapchat://' then 'Snapchat' + when 'paypal://' then 'PayPal' + when 'skype://' then 'Skype' + when 'discord://' then 'Discord' + when 'slack://' then 'Slack' + when 'zoomus://', 'zoom://' then 'Zoom' + when 'meet://' then 'Google Meet' + when 'waze://' then 'Waze' + when 'maps://' then 'Maps' + when 'uber://' then 'Uber' + when 'lyft://' then 'Lyft' + when 'cameraplus://' then 'Camera+' + when 'vimeo://' then 'Vimeo' + when 'tumblr://' then 'Tumblr' + when 'reddit://' then 'Reddit' + when 'hulu://' then 'Hulu' + when 'netflix://' then 'Netflix' + when 'soundcloud://' then 'SoundCloud' + when 'deezer://' then 'Deezer' + when 'tidal://' then 'Tidal' + when 'messenger://', 'fb-messenger://' then 'Messenger' + when 'skype-for-business://' then 'Skype for Business' + when 'teams://' then 'Microsoft Teams' + when 'onedrive://' then 'OneDrive' + when 'dropbox://' then 'Dropbox' + when 'box://' then 'Box' + when 'twitch://' then 'Twitch' + when 'quora://' then 'Quora' + when 'medium://' then 'Medium' + when 'goodreads://' then 'Goodreads' + when 'yelp://' then 'Yelp' + when 'tripadvisor://' then 'Tripadvisor' + when 'booking://' then 'Booking.com' + when 'airbnb://' then 'Airbnb' + when 'grabpay://' then 'GrabPay' + when 'wechatpay://' then 'WeChat Pay' + when 'ocbc://' then 'OCBC Bank' + when 'maybank2u://' then 'Maybank2u' + when 'rhb://' then 'RHB Bank' + when 'cimb://' then 'CIMB Bank' + when 'dbs://' then 'DBS Bank' + when 'hsbc://' then 'HSBC' + when 'standardchartered://' then 'Standard Chartered' + else 'Unknown App' + end + end + end \ No newline at end of file From 81128a0ab5c230502a85f95037e31cd8c897662f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=A8=F0=9F=87=B3=E9=92=9F=E6=99=BA=E5=BC=BA=20?= =?UTF-8?q?=E3=80=8E=E6=B1=9F=E8=A5=BF=E9=9D=92=E5=9E=A3=E7=A7=91=E6=8A=80?= =?UTF-8?q?=E3=80=8F?= Date: Fri, 31 Oct 2025 15:19:50 +0800 Subject: [PATCH 3/4] Feat: Enhance Android Deep Link QR Code Generator with expanded scheme options - Updated module usage comments for clarity and conciseness - Integrated a comprehensive list of deep link schemes into DEEPLINK_SCHEME options - Removed redundant @list_of_deeplink variable after integrating its contents into OptEnum --- ..._deeplinking_qr.rb => android_deeplink.rb} | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) rename modules/auxiliary/generator/{android_deeplinking_qr.rb => android_deeplink.rb} (92%) diff --git a/modules/auxiliary/generator/android_deeplinking_qr.rb b/modules/auxiliary/generator/android_deeplink.rb similarity index 92% rename from modules/auxiliary/generator/android_deeplinking_qr.rb rename to modules/auxiliary/generator/android_deeplink.rb index 60abe1a39d4fc..43c9941fb2e64 100644 --- a/modules/auxiliary/generator/android_deeplinking_qr.rb +++ b/modules/auxiliary/generator/android_deeplink.rb @@ -1,7 +1,4 @@ require 'msf/core' -require 'chunky_png' -require 'rqrcode' - class MetasploitModule < Msf::Auxiliary include Msf::Exploit::FILEFORMAT @@ -10,7 +7,7 @@ class MetasploitModule < Msf::Auxiliary # # 1. Load the module: # 2. Set the deep link scheme (like for Wechat lets say): - # `use auxiliary/generator/android_deeplinking_qr` + # `use auxiliary/generator/android_deeplink` # # `set DEEPLINK_SCHEME weixin://` # @@ -27,7 +24,7 @@ def initialize(info = {}) super(update_info(info, 'Name' => 'Android Deep Link QR Code Payload Generator', 'Description' => %q{ - This module make QR code with ANdroid Deep Link. + This module make QR code with Android Deep Link. When user scan QR, phone open app with deep link. Can use for test app security or social engineering. }, @@ -108,14 +105,20 @@ def initialize(info = {}) OptString.new('FILENAME', [true, 'QR code output file', 'deeplink_qr.png']), OptInt.new('SIZE', [true, 'QR code size in pixel', 400]) ]) - - # List for reference - # maybe add more in future - - end def run + unless check_gems_available + if datastore['INSTALL_GEMS'] + install_missing_gems + return + else + print_error("Required gems not found. Run: gem install rqrcode chunky_png") + print_error("Or set INSTALL_GEMS to true to install automatically") + return + end + end + scheme = datastore['DEEPLINK_SCHEME'] if scheme == 'custom://' @@ -148,6 +151,10 @@ def run print_status("This deep link will open: #{app_name}") begin + # Iput this here just in case + require 'rqrcode' + require 'chunky_png' + generate_qr_code(target_deep_link) print_good("QR code generate success: #{datastore['FILENAME']}") @@ -244,5 +251,4 @@ def get_app_name(scheme) else 'Unknown App' end end - end \ No newline at end of file From 238a25df9cfbe47ccce06a9f412fb566b5e083ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9F=87=A8=F0=9F=87=B3=E9=92=9F=E6=99=BA=E5=BC=BA=20?= =?UTF-8?q?=E3=80=8E=E6=B1=9F=E8=A5=BF=E9=9D=92=E5=9E=A3=E7=A7=91=E6=8A=80?= =?UTF-8?q?=E3=80=8F?= Date: Fri, 31 Oct 2025 15:30:01 +0800 Subject: [PATCH 4/4] Add Android deep link QR generator for mobile app security testing Create QR codes that trigger app actions when scanned, useful for testing deep link vulnerabilities and social engineering scenarios across popular apps. --- Gemfile | 3 ++ Gemfile.lock | 6 ++++ .../auxiliary/generator/android_deeplink.rb | 34 +++++++++---------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Gemfile b/Gemfile index 1d7e16841b6a3..7126694ae9ef0 100644 --- a/Gemfile +++ b/Gemfile @@ -55,3 +55,6 @@ group :test do gem 'timecop' end + +gem "rqrcode", "~> 3.1" +gem "chunky_png", "~> 1.4" diff --git a/Gemfile.lock b/Gemfile.lock index be5f87900ae18..6107c1be15968 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -536,6 +536,10 @@ GEM forwardable ipaddr rkelly-remix (0.0.7) + rqrcode (3.1.0) + chunky_png (~> 1.0) + rqrcode_core (~> 2.0) + rqrcode_core (2.0.0) rspec (3.13.1) rspec-core (~> 3.13.0) rspec-expectations (~> 3.13.0) @@ -669,6 +673,7 @@ PLATFORMS DEPENDENCIES allure-rspec + chunky_png (~> 1.4) debug (>= 1.0.0) factory_bot_rails fivemat @@ -679,6 +684,7 @@ DEPENDENCIES pry-byebug rake redcarpet + rqrcode (~> 3.1) rspec-rails rspec-rerun rubocop (= 1.75.7) diff --git a/modules/auxiliary/generator/android_deeplink.rb b/modules/auxiliary/generator/android_deeplink.rb index 43c9941fb2e64..86b22eee2ee90 100644 --- a/modules/auxiliary/generator/android_deeplink.rb +++ b/modules/auxiliary/generator/android_deeplink.rb @@ -4,7 +4,8 @@ class MetasploitModule < Msf::Auxiliary include Msf::Exploit::FILEFORMAT # How to use this module: - # + # + # Search: `search android_deeplink` to check for module # 1. Load the module: # 2. Set the deep link scheme (like for Wechat lets say): # `use auxiliary/generator/android_deeplink` @@ -108,15 +109,20 @@ def initialize(info = {}) end def run - unless check_gems_available - if datastore['INSTALL_GEMS'] - install_missing_gems - return - else - print_error("Required gems not found. Run: gem install rqrcode chunky_png") - print_error("Or set INSTALL_GEMS to true to install automatically") - return - end + + begin + require 'rqrcode' + require 'chunky_png' + gems_available = true + rescue LoadError + gems_available = false + end + + unless gems_available + print_error("Required gems not found. Please install them with:") + print_error("gem install rqrcode chunky_png") + print_error("Then restart msfconsole and try again.") + return end scheme = datastore['DEEPLINK_SCHEME'] @@ -151,20 +157,12 @@ def run print_status("This deep link will open: #{app_name}") begin - # Iput this here just in case - require 'rqrcode' - require 'chunky_png' - generate_qr_code(target_deep_link) - print_good("QR code generate success: #{datastore['FILENAME']}") print_warning("When user scan this QR, #{app_name} will open with deep link") rescue => e print_error("Generate QR code fail: #{e.message}") - if e.message.include?('missing constant') || e.message.include?('require') - print_error("Maybe need install gem: gem install rqrcode chunky_png") - end end end