Skip to content

Commit

Permalink
Added solver when n is prime. Fixed URL to factordb. Closes RsaCtfToo…
Browse files Browse the repository at this point in the history
  • Loading branch information
root committed Jan 1, 2019
1 parent c06454b commit 5acf41c
Showing 1 changed file with 41 additions and 5 deletions.
46 changes: 41 additions & 5 deletions RsaCtfTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
from Crypto.PublicKey import RSA
import signal
import gmpy2

from Crypto.Util.number import bytes_to_long, long_to_bytes

from rsalibnum import *
import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning
Expand Down Expand Up @@ -136,6 +139,7 @@ def __init__(self, args):
self.pubkeyfile = args.publickey
self.pub_key = PublicKey(key)
self.priv_key = None
self.partitial_priv_key = None
self.displayed = False # have we already spammed the user with this private key?
self.args = args
self.unciphered = None
Expand Down Expand Up @@ -210,12 +214,32 @@ def solveforp(equation):

# Factors available online?
try:
url_1 = 'https://factordb.com/index.php?query=%i'
url_2 = 'https://factordb.com/index.php?id=%s'
url_1 = 'http://factordb.com/index.php?query=%i'
url_2 = 'http://factordb.com/index.php?id=%s'
s = requests.Session()
r = s.get(url_1 % self.pub_key.n, verify=False)
regex = re.compile("index\.php\?id\=([0-9]+)", re.IGNORECASE)
ids = regex.findall(r.text)
# check if only 1 factor is returned
if len(ids) == 2:
# theres a chance that the only factor returned is prime, and so we can derive the priv key from it
regex = re.compile("<td>P<\/td>")
prime = regex.findall(r.text)
if len(prime) == 1:
# n is prime, so lets get the key from it
d = invmod(self.pub_key.e, self.pub_key.n - 1)
# construct key using only n and d
try:
# pycrypto >=2.5
impl = RSA.RSAImplementation(use_fast_math=False)
self.partitial_priv_key = impl.construct((self.pub_key.n, 0L))
self.partitial_priv_key.key.d = d
except TypeError:
# pycrypto <=2.4.1
self.partitial_priv_key = RSA.construct((self.pub_key.n, 0L, d))

return

p_id = ids[1]
q_id = ids[2]
# bugfix: See https://github.com/sourcekris/RsaCtfTool/commit/16d4bb258ebb4579aba2bfc185b3f717d2d91330#commitcomment-21878835
Expand Down Expand Up @@ -533,10 +557,16 @@ def attack(self):
getattr(self, attack.__name__)()

# check and print resulting private key
if self.priv_key is not None:
if self.priv_key is not None or self.partitial_priv_key is not None:
if self.args.private and not self.displayed:
print(self.priv_key)
if self.priv_key is not None:
print(self.priv_key)
else:
print("d: %i" % self.partitial_priv_key.key.d)
print("e: %i" % self.partitial_priv_key.key.e)
print("n: %i" % self.partitial_priv_key.key.n)
self.displayed = True

break

if self.unciphered is not None:
Expand All @@ -546,13 +576,19 @@ def attack(self):
if self.cipher and self.priv_key is not None:
self.unciphered = self.priv_key.decrypt(self.cipher)
print("[+] Clear text : %s" % str(self.unciphered))
elif self.cipher and self.partitial_priv_key is not None:
# needed, if n is prime and so we cant calc p and q
enc_msg = bytes_to_long(self.cipher)
dec_msg = self.partitial_priv_key.key._decrypt(enc_msg)
self.unciphered = long_to_bytes(dec_msg)
print("[+] Clear text : %s" % str(self.unciphered))
elif self.unciphered is not None:
print("[+] Clear text : %s" % str(self.unciphered))
else:
if self.cipher is not None and self.args.attack is None:
print("[-] Sorry, cracking failed")

if self.priv_key is None and self.args.private:
if self.priv_key is None and self.partitial_priv_key is None and self.args.private:
print("[-] Sorry, cracking failed")

implemented_attacks = [nullattack, hastads, factordb, pastctfprimes,
Expand Down

0 comments on commit 5acf41c

Please sign in to comment.