Skip to content

Commit

Permalink
Add support for sage modules via subprocess. Adds boneh_durfee() and …
Browse files Browse the repository at this point in the history
…smallfractions() attacks.
  • Loading branch information
sourcekris committed Apr 30, 2017
1 parent c81a698 commit 4b3ef54
Show file tree
Hide file tree
Showing 5 changed files with 393 additions and 318 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@ target/

# PyCharm
.idea/

# Sage stuff
*.sage.py
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ Automatic selection of best attack for the given public key
Attacks :
- Weak public key factorization
- Wiener's attack
- Hastad's attack (Small exponent attack)
- Small q (q<100,000)
- Hastad's attack (Small public exponent attack)
- Small q (q < 100,000)
- Common factor between ciphertext and modulus attack
- Fermat's factorisation for close p and q
- Gimmicky Primes method
- Past CTF Primes method
- Self-Initializing Quadratic Sieve (SIQS) using Yafu - NEW
- Common factor attacks across multiple keys - NEW
- Self-Initializing Quadratic Sieve (SIQS) using Yafu
- Common factor attacks across multiple keys
- Small fractions method when p/q is close to a small fraction
- Boneh Durfee Method when the private exponent d is too small compared to the modulus (i.e d < n^0.292)

## Usage:
usage: RsaCtfTool.py [-h] \(--publickey PUBLICKEY | --createpub | --dumpkey\)
Expand Down Expand Up @@ -49,21 +51,25 @@ Mode 3 - Dump the public and/or private numbers from a PEM/DER format public or
#### Examples :
- weak\_public.pub, weak\_public.cipher : weak public key
- wiener.pub, wiener.cipher : key vulnerable to Wiener's attack
- small\exponent.pub, small\_exponent.cipher : key with e=3, vulnerable to Hastad's attack
- small\_exponent.pub, small\_exponent.cipher : key with e=3, vulnerable to Hastad's attack
- small\_q.pub, small\_q.cipher : public key with a small prime
- close\_primes.pub, close\_primes.cipher : public key with primes suceptible to fermat factorization
- elite\_primes.pub : public key with a gimmick prime
- fermat.pub : public key with another vulnerability to fermat factorization
- pastctfprimes.pub : public key with a prime from a past CTF
- siqs.pub: 256bit public key that is factored in 30 seconds with SIQS
- factordb_parsing.pub: a public key with a prime that is described as an expression on factordb.com
- smallfraction.pub: a public key where p/q is close to a small fraction
- boneh\_durfee.pub: a public key factorable using boneh\_durfee method
- multikey-0.pub and multikey-1.pub: Public keys that share a common factor

#### Requirements:
- GMPY
- SymPy
- libnum (https://github.com/hellman/libnum.git)
- PyCrypto
- Requests
- SageMath - optional but advisable

### MacOS-specific Instructions
If `pip install -r "requirements.txt"` fails to install requirements accessible within environment, the following command may work.
Expand Down
62 changes: 58 additions & 4 deletions RsaCtfTool.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import requests
import re
import argparse
import subprocess
from glob import glob


Expand Down Expand Up @@ -91,12 +92,18 @@ def __init__(self, args):
self.args = args
self.unciphered = None
self.attackobjs = None # This is how we'll know this object represents 1 key

# Test if sage is working and if so, load additional sage based attacks
if args.sageworks:
self.implemented_attacks.append(self.smallfraction)
self.implemented_attacks.append(self.boneh_durfee)

# Load ciphertext
if args.uncipher is not None:
self.cipher = open(args.uncipher, 'rb').read().strip()
else:
self.cipher = None
return
return

def hastads(self):
# Hastad attack for low public exponent, this has found success for e = 3, and e = 5 previously
Expand All @@ -114,9 +121,9 @@ def hastads(self):
def factordb(self):
# if factordb returns some math to derive the prime, solve for p without using an eval
def solveforp(equation):
if '^' in equation: k,j = equation.split('^')
if '-' in j: j,sub = j.split('-')
try:
if '^' in equation: k,j = equation.split('^')
if '-' in j: j,sub = j.split('-')
eq = map(int, [k,j,sub])
return pow(eq[0],eq[1])-eq[2]
except Exception as e:
Expand Down Expand Up @@ -169,6 +176,25 @@ def wiener(self):

return

def boneh_durfee(self):
# use boneh durfee method, should return a d value, else returns 0
# only works if the sageworks() function returned True
# many of these problems will be solved by the wiener attack module but perhaps some will fall through to here
# TODO: get an example public key solvable by boneh_durfee but not wiener
sageresult = int(subprocess.check_output(['sage','boneh_durfee.sage',str(self.pub_key.n),str(self.pub_key.e)]))

if sageresult > 0:
# use PyCrypto _slowmath rsa_construct to resolve p and q from d
from Crypto.PublicKey import _slowmath
tmp_priv = _slowmath.rsa_construct(long(self.pub_key.n), long(self.pub_key.e), d=long(sageresult))

self.pub_key.p = tmp_priv.p
self.pub_key.q = tmp_priv.q
self.priv_key = PrivateKey(long(self.pub_key.p), long(self.pub_key.q),
long(self.pub_key.e), long(self.pub_key.n))

return

def smallq(self):
# Try an attack where q < 100,000, from BKPCTF2016 - sourcekris
for prime in primes(100000):
Expand All @@ -180,6 +206,17 @@ def smallq(self):

return

def smallfraction(self):
# Code/idea from Renaud Lifchitz's talk 15 ways to break RSA security @ OPCDE17
# only works if the sageworks() function returned True
sageresult = int(subprocess.check_output(['sage', 'smallfraction.sage',str(self.pub_key.n)]))
if sageresult > 0:
self.pub_key.p = sageresult
self.pub_key.q = self.pub_key.n / self.pub_key.p
self.priv_key = PrivateKey(long(self.pub_key.p), long(self.pub_key.q),
long(self.pub_key.e), long(self.pub_key.n))
return

def fermat(self, fermat_timeout=60):
# Try an attack where the primes are too close together from BKPCTF2016 - sourcekris
# this attack module can be optional
Expand Down Expand Up @@ -343,7 +380,6 @@ def attack(self):
print "[-] Sorry, cracking failed"

implemented_attacks = [ nullattack, hastads, factordb, pastctfprimes, noveltyprimes, smallq, wiener, comfact_cn, fermat, siqs ]


# source http://stackoverflow.com/a/22348885
class timeout:
Expand All @@ -361,6 +397,19 @@ def __enter__(self):
def __exit__(self, type, value, traceback):
signal.alarm(0)

def sageworks():
# Check if sage is installed and working
try:
sageversion = subprocess.check_output(['sage', '-v'])
except OSError:
return False

if 'SageMath version' in sageversion:

return True
else:
return False

if __name__ == "__main__":
parser = argparse.ArgumentParser(description='RSA CTF Tool Continued')
group = parser.add_mutually_exclusive_group(required=True)
Expand Down Expand Up @@ -398,6 +447,11 @@ def __exit__(self, type, value, traceback):
print "[*] q: " + str(key.q)
quit()

if sageworks():
args.sageworks = True
else:
args.sageworks = False

attackobj = RSAAttack(args)
attackobj.attack()

Loading

0 comments on commit 4b3ef54

Please sign in to comment.