15
15
from Crypto .PublicKey import RSA
16
16
import signal
17
17
import gmpy2
18
+
19
+ from Crypto .Util .number import bytes_to_long , long_to_bytes
20
+
18
21
from rsalibnum import *
19
22
import requests
20
23
from requests .packages .urllib3 .exceptions import InsecureRequestWarning
@@ -136,6 +139,7 @@ def __init__(self, args):
136
139
self .pubkeyfile = args .publickey
137
140
self .pub_key = PublicKey (key )
138
141
self .priv_key = None
142
+ self .partitial_priv_key = None
139
143
self .displayed = False # have we already spammed the user with this private key?
140
144
self .args = args
141
145
self .unciphered = None
@@ -210,12 +214,32 @@ def solveforp(equation):
210
214
211
215
# Factors available online?
212
216
try :
213
- url_1 = 'https ://factordb.com/index.php?query=%i'
214
- url_2 = 'https ://factordb.com/index.php?id=%s'
217
+ url_1 = 'http ://factordb.com/index.php?query=%i'
218
+ url_2 = 'http ://factordb.com/index.php?id=%s'
215
219
s = requests .Session ()
216
220
r = s .get (url_1 % self .pub_key .n , verify = False )
217
221
regex = re .compile ("index\.php\?id\=([0-9]+)" , re .IGNORECASE )
218
222
ids = regex .findall (r .text )
223
+ # check if only 1 factor is returned
224
+ if len (ids ) == 2 :
225
+ # theres a chance that the only factor returned is prime, and so we can derive the priv key from it
226
+ regex = re .compile ("<td>P<\/td>" )
227
+ prime = regex .findall (r .text )
228
+ if len (prime ) == 1 :
229
+ # n is prime, so lets get the key from it
230
+ d = invmod (self .pub_key .e , self .pub_key .n - 1 )
231
+ # construct key using only n and d
232
+ try :
233
+ # pycrypto >=2.5
234
+ impl = RSA .RSAImplementation (use_fast_math = False )
235
+ self .partitial_priv_key = impl .construct ((self .pub_key .n , 0L ))
236
+ self .partitial_priv_key .key .d = d
237
+ except TypeError :
238
+ # pycrypto <=2.4.1
239
+ self .partitial_priv_key = RSA .construct ((self .pub_key .n , 0L , d ))
240
+
241
+ return
242
+
219
243
p_id = ids [1 ]
220
244
q_id = ids [2 ]
221
245
# bugfix: See https://github.com/sourcekris/RsaCtfTool/commit/16d4bb258ebb4579aba2bfc185b3f717d2d91330#commitcomment-21878835
@@ -533,10 +557,16 @@ def attack(self):
533
557
getattr (self , attack .__name__ )()
534
558
535
559
# check and print resulting private key
536
- if self .priv_key is not None :
560
+ if self .priv_key is not None or self . partitial_priv_key is not None :
537
561
if self .args .private and not self .displayed :
538
- print (self .priv_key )
562
+ if self .priv_key is not None :
563
+ print (self .priv_key )
564
+ else :
565
+ print ("d: %i" % self .partitial_priv_key .key .d )
566
+ print ("e: %i" % self .partitial_priv_key .key .e )
567
+ print ("n: %i" % self .partitial_priv_key .key .n )
539
568
self .displayed = True
569
+
540
570
break
541
571
542
572
if self .unciphered is not None :
@@ -546,13 +576,19 @@ def attack(self):
546
576
if self .cipher and self .priv_key is not None :
547
577
self .unciphered = self .priv_key .decrypt (self .cipher )
548
578
print ("[+] Clear text : %s" % str (self .unciphered ))
579
+ elif self .cipher and self .partitial_priv_key is not None :
580
+ # needed, if n is prime and so we cant calc p and q
581
+ enc_msg = bytes_to_long (self .cipher )
582
+ dec_msg = self .partitial_priv_key .key ._decrypt (enc_msg )
583
+ self .unciphered = long_to_bytes (dec_msg )
584
+ print ("[+] Clear text : %s" % str (self .unciphered ))
549
585
elif self .unciphered is not None :
550
586
print ("[+] Clear text : %s" % str (self .unciphered ))
551
587
else :
552
588
if self .cipher is not None and self .args .attack is None :
553
589
print ("[-] Sorry, cracking failed" )
554
590
555
- if self .priv_key is None and self .args .private :
591
+ if self .priv_key is None and self .partitial_priv_key is None and self . args .private :
556
592
print ("[-] Sorry, cracking failed" )
557
593
558
594
implemented_attacks = [nullattack , hastads , factordb , pastctfprimes ,
0 commit comments