21
21
import requests
22
22
import re
23
23
import argparse
24
+ import subprocess
24
25
from glob import glob
25
26
26
27
@@ -91,12 +92,18 @@ def __init__(self, args):
91
92
self .args = args
92
93
self .unciphered = None
93
94
self .attackobjs = None # This is how we'll know this object represents 1 key
95
+
96
+ # Test if sage is working and if so, load additional sage based attacks
97
+ if args .sageworks :
98
+ self .implemented_attacks .append (self .smallfraction )
99
+ self .implemented_attacks .append (self .boneh_durfee )
100
+
94
101
# Load ciphertext
95
102
if args .uncipher is not None :
96
103
self .cipher = open (args .uncipher , 'rb' ).read ().strip ()
97
104
else :
98
105
self .cipher = None
99
- return
106
+ return
100
107
101
108
def hastads (self ):
102
109
# Hastad attack for low public exponent, this has found success for e = 3, and e = 5 previously
@@ -114,9 +121,9 @@ def hastads(self):
114
121
def factordb (self ):
115
122
# if factordb returns some math to derive the prime, solve for p without using an eval
116
123
def solveforp (equation ):
117
- if '^' in equation : k ,j = equation .split ('^' )
118
- if '-' in j : j ,sub = j .split ('-' )
119
124
try :
125
+ if '^' in equation : k ,j = equation .split ('^' )
126
+ if '-' in j : j ,sub = j .split ('-' )
120
127
eq = map (int , [k ,j ,sub ])
121
128
return pow (eq [0 ],eq [1 ])- eq [2 ]
122
129
except Exception as e :
@@ -169,6 +176,25 @@ def wiener(self):
169
176
170
177
return
171
178
179
+ def boneh_durfee (self ):
180
+ # use boneh durfee method, should return a d value, else returns 0
181
+ # only works if the sageworks() function returned True
182
+ # many of these problems will be solved by the wiener attack module but perhaps some will fall through to here
183
+ # TODO: get an example public key solvable by boneh_durfee but not wiener
184
+ sageresult = int (subprocess .check_output (['sage' ,'boneh_durfee.sage' ,str (self .pub_key .n ),str (self .pub_key .e )]))
185
+
186
+ if sageresult > 0 :
187
+ # use PyCrypto _slowmath rsa_construct to resolve p and q from d
188
+ from Crypto .PublicKey import _slowmath
189
+ tmp_priv = _slowmath .rsa_construct (long (self .pub_key .n ), long (self .pub_key .e ), d = long (sageresult ))
190
+
191
+ self .pub_key .p = tmp_priv .p
192
+ self .pub_key .q = tmp_priv .q
193
+ self .priv_key = PrivateKey (long (self .pub_key .p ), long (self .pub_key .q ),
194
+ long (self .pub_key .e ), long (self .pub_key .n ))
195
+
196
+ return
197
+
172
198
def smallq (self ):
173
199
# Try an attack where q < 100,000, from BKPCTF2016 - sourcekris
174
200
for prime in primes (100000 ):
@@ -180,6 +206,17 @@ def smallq(self):
180
206
181
207
return
182
208
209
+ def smallfraction (self ):
210
+ # Code/idea from Renaud Lifchitz's talk 15 ways to break RSA security @ OPCDE17
211
+ # only works if the sageworks() function returned True
212
+ sageresult = int (subprocess .check_output (['sage' , 'smallfraction.sage' ,str (self .pub_key .n )]))
213
+ if sageresult > 0 :
214
+ self .pub_key .p = sageresult
215
+ self .pub_key .q = self .pub_key .n / self .pub_key .p
216
+ self .priv_key = PrivateKey (long (self .pub_key .p ), long (self .pub_key .q ),
217
+ long (self .pub_key .e ), long (self .pub_key .n ))
218
+ return
219
+
183
220
def fermat (self , fermat_timeout = 60 ):
184
221
# Try an attack where the primes are too close together from BKPCTF2016 - sourcekris
185
222
# this attack module can be optional
@@ -343,7 +380,6 @@ def attack(self):
343
380
print "[-] Sorry, cracking failed"
344
381
345
382
implemented_attacks = [ nullattack , hastads , factordb , pastctfprimes , noveltyprimes , smallq , wiener , comfact_cn , fermat , siqs ]
346
-
347
383
348
384
# source http://stackoverflow.com/a/22348885
349
385
class timeout :
@@ -361,6 +397,19 @@ def __enter__(self):
361
397
def __exit__ (self , type , value , traceback ):
362
398
signal .alarm (0 )
363
399
400
+ def sageworks ():
401
+ # Check if sage is installed and working
402
+ try :
403
+ sageversion = subprocess .check_output (['sage' , '-v' ])
404
+ except OSError :
405
+ return False
406
+
407
+ if 'SageMath version' in sageversion :
408
+
409
+ return True
410
+ else :
411
+ return False
412
+
364
413
if __name__ == "__main__" :
365
414
parser = argparse .ArgumentParser (description = 'RSA CTF Tool Continued' )
366
415
group = parser .add_mutually_exclusive_group (required = True )
@@ -398,6 +447,11 @@ def __exit__(self, type, value, traceback):
398
447
print "[*] q: " + str (key .q )
399
448
quit ()
400
449
450
+ if sageworks ():
451
+ args .sageworks = True
452
+ else :
453
+ args .sageworks = False
454
+
401
455
attackobj = RSAAttack (args )
402
456
attackobj .attack ()
403
457
0 commit comments