From 6f333dc094a5bea3dc85c14a2d6fa79066a67919 Mon Sep 17 00:00:00 2001 From: Srikanth L Date: Tue, 3 May 2022 15:40:57 +0000 Subject: [PATCH 1/6] Added GPay UPI VPA search by GMail account --- .gitignore | 1 + config/config.ini | 2 -- config/config.ini.sample | 2 ++ upi-recon.py | 21 ++++++++++++++++++--- 4 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 .gitignore delete mode 100644 config/config.ini create mode 100644 config/config.ini.sample diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4bfe59e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config/config.ini diff --git a/config/config.ini b/config/config.ini deleted file mode 100644 index 400f249..0000000 --- a/config/config.ini +++ /dev/null @@ -1,2 +0,0 @@ -[main] -api_key_id = key_goes_here \ No newline at end of file diff --git a/config/config.ini.sample b/config/config.ini.sample new file mode 100644 index 0000000..934f96a --- /dev/null +++ b/config/config.ini.sample @@ -0,0 +1,2 @@ +[main] +api_key_id = YOUR_KEY_HERE diff --git a/upi-recon.py b/upi-recon.py index 121c8d7..c70b0a5 100644 --- a/upi-recon.py +++ b/upi-recon.py @@ -27,10 +27,12 @@ # Usage: upi-recon.py [query all possible UPI addresses] upi-recon.py -t 5 [query all possible UPI addresses with specified number of threads] upi-recon.py -s [query a single UPI address with a specific suffix] + upi-recon.py -g [query all possible Google Pay UPI addresses for specified google account] """ upi_suffix_dict = ['airtel', 'airtelpaymentsbank', 'apl', 'abfspay', 'allbank', 'andb', 'aubank', 'axis', 'albk', 'allahabadbank', 'apb', 'axisb', 'axisbank', 'axisgo', 'barodampay', 'barodapay', 'bandhan', 'birla', 'boi', 'cbin', 'cboi', 'centralbank', 'cnrb', 'dlb', 'eazypay', 'ezeepay', 'fbl', 'federal', 'freecharge', 'cmsidfc', 'csbcash', 'csbpay', 'cub', 'dbs', 'dcb', 'denabank', 'equitas', 'finobank', 'hdfcbank', 'hdfcbankjd', 'hsbc', 'ibl', 'icici', 'idbi', 'idbibank', 'idfcbank', 'icicibank', 'idfc', 'idfcnetc', 'ikwik', 'imobile', 'indianbank', 'indus', 'jkb', 'karurvysyabank', 'kaypay', 'kbl', 'kmb', 'kmbl', 'kotak', 'kvb', 'kvbank', 'lime', 'mahb', 'myicici', 'obc', 'okaxis', 'okhdfcbank', 'okicici', 'oksbi', 'paytm', 'payzapp', 'pingpay', 'pnb', 'pockets', 'rajgovhdfcbank', 'rbl', 'rmhdfcbank', 'sbi', 'sib', 'ubi', 'uboi', 'uco', 'unionbank', 'unionbankofindia', 'united', 'upi', 'utbi', 'ybl', 'yesbank', 'yesbankltd', 'indbank', 'indianbk', 'iob', 'jsbp', 'karb', 'lvb', 'lvbank', 'psb', 'purz', 'sc', 'scb', 'scbl', 'scmobile', 'srcb', 'synd', 'syndbank', 'syndicate', 'tjsb', 'vijayabank', 'vijb', 'vjb'] +gpay_suffix_dict = ['okicici', 'oksbi', 'okaxis', 'okhdfcbank'] def address_discovery(vpa, api_url): try: @@ -51,7 +53,7 @@ def address_discovery(vpa, api_url): # argument definition parser = argparse.ArgumentParser(description='fetch UPI addresses and associated information for a given phone number') # primary arguments - parser.add_argument('phone', type=str, help='phone number to query UPI addresses for') + parser.add_argument('-p', '--phone', type=str, help='phone number to query UPI addresses for') parser.add_argument('-t', '--threads', type=int, default=None, help='number of threads to use for parallel address discovery') parser.add_argument('-q', '--quiet', default=False, action='store_true', help='suppress banner') # group arguments @@ -60,6 +62,8 @@ def address_discovery(vpa, api_url): group_2 = parser.add_mutually_exclusive_group() group_2.add_argument('-a', '--all', default=True, action='store_true', help='query all suffixes') group_2.add_argument('-s', '--suffix', type=str, help='query a specific suffix') + group_3 = parser.add_mutually_exclusive_group() + group_3.add_argument('-g', '--gpay', type=str, help='enter gmail id without @gmail.com') # parse arguments arguments = parser.parse_args() # check the configuration @@ -76,7 +80,11 @@ def address_discovery(vpa, api_url): # set variables and normalize input API_URL = 'https://api.razorpay.com/v1/payments/validate/account?key_id=' api_key_id = config.get('main', 'api_key_id') - phone = arguments.phone[2:] if arguments.phone[0:2] == '91' else arguments.phone + if arguments.gpay: + email = arguments.gpay + phone = '8888888888' + else: + phone = arguments.phone[2:] if arguments.phone[0:2] == '91' else arguments.phone # check if api_key_id is correct if api_key_id and not api_key_id[0:3] == 'rzp': quit('[!] invalid api_key_id') @@ -94,6 +102,13 @@ def address_discovery(vpa, api_url): print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) exit(1) + elif arguments.gpay: + print('[i] querying Google Pay UPI addresses for email ' + email + '@gmail.com') + for suffix in gpay_suffix_dict: + address_discovery(email + '@' + suffix, API_URL + api_key_id) + print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) + exit(1) + elif arguments.all and not arguments.threads: # query all with no concurrency print('[i] querying UPI addresses for phone number ' + phone) for suffix in track(upi_suffix_dict): @@ -112,4 +127,4 @@ def address_discovery(vpa, api_url): print('\n[!] interrupted! stopping threads...') exit(1) print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) - exit(1) \ No newline at end of file + exit(1) From 2fbfce1764482e0e195d8097b177a9af57246063 Mon Sep 17 00:00:00 2001 From: qurbat Date: Wed, 4 May 2022 00:38:22 +0530 Subject: [PATCH 2/6] introduce gpay support (#2) --- README.md | 9 ++++++--- config/config.ini.example | 2 ++ config/config.ini.sample | 2 -- upi-recon.py | 9 ++++++--- 4 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 config/config.ini.example delete mode 100644 config/config.ini.sample diff --git a/README.md b/README.md index 5f278b9..dc844c0 100644 --- a/README.md +++ b/README.md @@ -16,11 +16,14 @@ Please [refer to the documentation](https://razorpay.com/docs/payments/dashboard ## Usage ### Query all possible UPI addresses for the provided phone number -`upi-recon.py ` +`upi-recon.py -p ` ### Query all possible UPI addresses for the provided phone number using a specified number of threads -`upi-recon.py -t 5` +`upi-recon.py -p -t 5` ### Query a single UPI address for the provided phone number using a provided suffix -`upi-recon.py -s ` +`upi-recon.py -p -s ` +### Query all possible UPI addresses for the provided Gmail address +`upi-recon.py -g ` + ## Contributions Contributions are welcome. Feature wishlist: diff --git a/config/config.ini.example b/config/config.ini.example new file mode 100644 index 0000000..d33b16c --- /dev/null +++ b/config/config.ini.example @@ -0,0 +1,2 @@ +[main] +api_key_id = your_key_goes_here \ No newline at end of file diff --git a/config/config.ini.sample b/config/config.ini.sample deleted file mode 100644 index 934f96a..0000000 --- a/config/config.ini.sample +++ /dev/null @@ -1,2 +0,0 @@ -[main] -api_key_id = YOUR_KEY_HERE diff --git a/upi-recon.py b/upi-recon.py index c70b0a5..7a51dae 100644 --- a/upi-recon.py +++ b/upi-recon.py @@ -2,9 +2,9 @@ # -*- coding: utf-8 -*- import argparse +import os import requests import concurrent.futures -import signal from time import sleep from random import uniform as rand @@ -53,7 +53,6 @@ def address_discovery(vpa, api_url): # argument definition parser = argparse.ArgumentParser(description='fetch UPI addresses and associated information for a given phone number') # primary arguments - parser.add_argument('-p', '--phone', type=str, help='phone number to query UPI addresses for') parser.add_argument('-t', '--threads', type=int, default=None, help='number of threads to use for parallel address discovery') parser.add_argument('-q', '--quiet', default=False, action='store_true', help='suppress banner') # group arguments @@ -63,10 +62,14 @@ def address_discovery(vpa, api_url): group_2.add_argument('-a', '--all', default=True, action='store_true', help='query all suffixes') group_2.add_argument('-s', '--suffix', type=str, help='query a specific suffix') group_3 = parser.add_mutually_exclusive_group() + group_3.add_argument('-p', '--phone', type=str, help='phone number to query UPI addresses for') group_3.add_argument('-g', '--gpay', type=str, help='enter gmail id without @gmail.com') # parse arguments arguments = parser.parse_args() # check the configuration + if not os.path.exists('config/config.ini'): + print('[!] config.ini not found. please create one with config.ini.example') + exit(1) config = ConfigParser() config_file = 'config/config.ini' config.read(config_file) @@ -84,7 +87,7 @@ def address_discovery(vpa, api_url): email = arguments.gpay phone = '8888888888' else: - phone = arguments.phone[2:] if arguments.phone[0:2] == '91' else arguments.phone + phone = arguments.phone[2:] if arguments.phone[0:2] == '91' and len(arguments.phone) > 10 else arguments.phone # check if api_key_id is correct if api_key_id and not api_key_id[0:3] == 'rzp': quit('[!] invalid api_key_id') From 635c8d288e465a81e58175fae5e2ec9253d1691a Mon Sep 17 00:00:00 2001 From: qurbat Date: Wed, 4 May 2022 00:45:53 +0530 Subject: [PATCH 3/6] use track() for gpay queries --- upi-recon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upi-recon.py b/upi-recon.py index 7a51dae..ecbda12 100644 --- a/upi-recon.py +++ b/upi-recon.py @@ -107,7 +107,7 @@ def address_discovery(vpa, api_url): elif arguments.gpay: print('[i] querying Google Pay UPI addresses for email ' + email + '@gmail.com') - for suffix in gpay_suffix_dict: + for suffix in track(gpay_suffix_dict): address_discovery(email + '@' + suffix, API_URL + api_key_id) print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) exit(1) From 73300cefda9bd0925095811e0b7e59e0ef6ca985 Mon Sep 17 00:00:00 2001 From: qurbat Date: Wed, 4 May 2022 01:30:15 +0530 Subject: [PATCH 4/6] fix argument parsing --- upi-recon.py | 66 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 19 deletions(-) diff --git a/upi-recon.py b/upi-recon.py index ecbda12..17c5f43 100644 --- a/upi-recon.py +++ b/upi-recon.py @@ -24,10 +24,10 @@ # Author: Karan Saini (@squeal) # URL: https://github.com/qurbat/upi-recon - # Usage: upi-recon.py [query all possible UPI addresses] - upi-recon.py -t 5 [query all possible UPI addresses with specified number of threads] - upi-recon.py -s [query a single UPI address with a specific suffix] - upi-recon.py -g [query all possible Google Pay UPI addresses for specified google account] + # Usage: upi-recon.py (query all possible UPI addresses) + upi-recon.py -t 5 (query all possible UPI addresses with specified number of threads) + upi-recon.py -s (query a single UPI address with a specific suffix) + upi-recon.py -g (query common Google Pay UPI addresses for specified google account) """ upi_suffix_dict = ['airtel', 'airtelpaymentsbank', 'apl', 'abfspay', 'allbank', 'andb', 'aubank', 'axis', 'albk', 'allahabadbank', 'apb', 'axisb', 'axisbank', 'axisgo', 'barodampay', 'barodapay', 'bandhan', 'birla', 'boi', 'cbin', 'cboi', 'centralbank', 'cnrb', 'dlb', 'eazypay', 'ezeepay', 'fbl', 'federal', 'freecharge', 'cmsidfc', 'csbcash', 'csbpay', 'cub', 'dbs', 'dcb', 'denabank', 'equitas', 'finobank', 'hdfcbank', 'hdfcbankjd', 'hsbc', 'ibl', 'icici', 'idbi', 'idbibank', 'idfcbank', 'icicibank', 'idfc', 'idfcnetc', 'ikwik', 'imobile', 'indianbank', 'indus', 'jkb', 'karurvysyabank', 'kaypay', 'kbl', 'kmb', 'kmbl', 'kotak', 'kvb', 'kvbank', 'lime', 'mahb', 'myicici', 'obc', 'okaxis', 'okhdfcbank', 'okicici', 'oksbi', 'paytm', 'payzapp', 'pingpay', 'pnb', 'pockets', 'rajgovhdfcbank', 'rbl', 'rmhdfcbank', 'sbi', 'sib', 'ubi', 'uboi', 'uco', 'unionbank', 'unionbankofindia', 'united', 'upi', 'utbi', 'ybl', 'yesbank', 'yesbankltd', 'indbank', 'indianbk', 'iob', 'jsbp', 'karb', 'lvb', 'lvbank', 'psb', 'purz', 'sc', 'scb', 'scbl', 'scmobile', 'srcb', 'synd', 'syndbank', 'syndicate', 'tjsb', 'vijayabank', 'vijb', 'vjb'] @@ -62,8 +62,8 @@ def address_discovery(vpa, api_url): group_2.add_argument('-a', '--all', default=True, action='store_true', help='query all suffixes') group_2.add_argument('-s', '--suffix', type=str, help='query a specific suffix') group_3 = parser.add_mutually_exclusive_group() - group_3.add_argument('-p', '--phone', type=str, help='phone number to query UPI addresses for') - group_3.add_argument('-g', '--gpay', type=str, help='enter gmail id without @gmail.com') + group_3.add_argument('phone', type=str, nargs='?', help='phone number to query UPI addresses for') + group_3.add_argument('-g', '--gpay', type=str, nargs='?', help='enter gmail address to query Google Pay UPI addresses for') # parse arguments arguments = parser.parse_args() # check the configuration @@ -83,21 +83,34 @@ def address_discovery(vpa, api_url): # set variables and normalize input API_URL = 'https://api.razorpay.com/v1/payments/validate/account?key_id=' api_key_id = config.get('main', 'api_key_id') - if arguments.gpay: - email = arguments.gpay + if not arguments.gpay and not arguments.phone: + print('[!] please enter a phone number or gmail address') + exit(1) + if arguments.gpay and not arguments.phone: + email = arguments.gpay[:-10] if arguments.gpay.endswith('@gmail.com') else arguments.gpay phone = '8888888888' - else: + elif arguments.phone and arguments.gpay: + print('[!] please enter either a phone number or a gmail address') + exit(1) + elif arguments.phone: phone = arguments.phone[2:] if arguments.phone[0:2] == '91' and len(arguments.phone) > 10 else arguments.phone + if len(phone) != 10: + print('[!] please enter a valid 10 digit phone number') + exit(1) # check if api_key_id is correct if api_key_id and not api_key_id[0:3] == 'rzp': quit('[!] invalid api_key_id') if not phone.isdigit(): - quit('[!] phone number must be numeric') + quit('[!] phone number must be numeric. use -g to query Google Pay addresses') # informational header print('[i] starting at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) # do the thing - if arguments.suffix: # query one + if arguments.suffix and arguments.gpay: + print('[!] cannot use suffix and gpay at the same time. please specify only one.') + exit(1) + + elif arguments.suffix: arguments.all = False suffix = arguments.suffix[1:] if arguments.suffix[0] == '@' else arguments.suffix print('[i] querying UPI addresses for phone number ' + phone) @@ -106,11 +119,24 @@ def address_discovery(vpa, api_url): exit(1) elif arguments.gpay: - print('[i] querying Google Pay UPI addresses for email ' + email + '@gmail.com') - for suffix in track(gpay_suffix_dict): - address_discovery(email + '@' + suffix, API_URL + api_key_id) - print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) - exit(1) + if arguments.threads: + print('[i] querying Google Pay UPI addresses for ' + email + '@gmail.com with ' + str(arguments.threads) + ' threads') + with concurrent.futures.ThreadPoolExecutor(max_workers=arguments.threads) as executor: + for suffix in gpay_suffix_dict: + try: + executor.submit(address_discovery, email + '@' + suffix, API_URL + api_key_id) + sleep(rand(0.1, 0.2)) + except KeyboardInterrupt as e: + print('\n[!] interrupted! stopping threads...') + exit(1) + print ('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) + exit(1) + else: + print('[i] querying Google Pay UPI addresses for ' + email + '@gmail.com') + for suffix in track(gpay_suffix_dict): + address_discovery(email + '@' + suffix, API_URL + api_key_id) + print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) + exit(1) elif arguments.all and not arguments.threads: # query all with no concurrency print('[i] querying UPI addresses for phone number ' + phone) @@ -119,8 +145,8 @@ def address_discovery(vpa, api_url): print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) exit(1) - elif arguments.threads: # query all with threading - print('[i] querying UPI addresses for phone number ' + phone) + elif arguments.threads and not arguments.gpay: # query all with threading + print('[i] querying UPI addresses for phone number ' + phone + ' with ' + str(arguments.threads) + ' threads') with concurrent.futures.ThreadPoolExecutor(max_workers=arguments.threads) as executor: for suffix in upi_suffix_dict: try: @@ -129,5 +155,7 @@ def address_discovery(vpa, api_url): except KeyboardInterrupt: print('\n[!] interrupted! stopping threads...') exit(1) - print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) + finally: + print('[i] finished at ' + datetime.now().strftime("%d/%m/%Y %H:%M:%S")) + exit(1) exit(1) From b00f8a81081deb00f0f691af8123a453ce3f8804 Mon Sep 17 00:00:00 2001 From: qurbat Date: Wed, 4 May 2022 01:41:04 +0530 Subject: [PATCH 5/6] config file changes --- upi-recon.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upi-recon.py b/upi-recon.py index 17c5f43..feec95b 100644 --- a/upi-recon.py +++ b/upi-recon.py @@ -68,7 +68,7 @@ def address_discovery(vpa, api_url): arguments = parser.parse_args() # check the configuration if not os.path.exists('config/config.ini'): - print('[!] config.ini not found. please create one with config.ini.example') + print('[!] config/config.ini not found! please create the config file\n[!] you may refer to config/config.ini.example for help') exit(1) config = ConfigParser() config_file = 'config/config.ini' From 7bc0e388b0792223bb9d32cb6b6fd4633f079ac6 Mon Sep 17 00:00:00 2001 From: qurbat Date: Wed, 4 May 2022 01:41:55 +0530 Subject: [PATCH 6/6] update readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index dc844c0..6ea7937 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ Please [refer to the documentation](https://razorpay.com/docs/payments/dashboard ## Contributions Contributions are welcome. Feature wishlist: +- [x] Introduce support for Google Pay addresses - [ ] Introduce support for more API providers - [ ] Introduce support for wordlist based address discovery - [ ] Improve argument parsing code