{"id":1210,"date":"2019-03-31T15:03:36","date_gmt":"2019-03-31T15:03:36","guid":{"rendered":"https:\/\/devel0pment.de\/?p=1210"},"modified":"2019-03-31T15:58:16","modified_gmt":"2019-03-31T15:58:16","slug":"volgactf-2019-qualifier-blind","status":"publish","type":"post","link":"https:\/\/devel0pment.de\/?p=1210","title":{"rendered":"VolgaCTF 2019 Qualifier &#8211; Blind"},"content":{"rendered":"<p><style>\n  .spanFlag {<br \/>\n    color:#0000ff;<br \/>\n    font-weight:bold;<br \/>\n  }<br \/>\n  code {<br \/>\n    font-size:16px;<br \/>\n    color:#0d5bd8;<br \/>\n  }<br \/>\n<\/style><\/p>\n<p>The <a href=\"https:\/\/q.2019.volgactf.ru\/\" target=\"_blank\" rel=\"noopener noreferrer\">VolgaCTF 2019 Qualifier<\/a> (<a href=\"https:\/\/ctftime.org\/event\/713\" target=\"_blank\" rel=\"noopener noreferrer\">ctftime.org<\/a>) took place from 29\/03\/2019, 15:00 UTC to 31\/03\/2019 15:00 UTC.<\/p>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-1211\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/03\/volgactf.jpg\" alt=\"\" width=\"340\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/03\/volgactf.jpg 512w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/03\/volgactf-300x200.jpg 300w\" sizes=\"(max-width: 512px) 100vw, 512px\" \/><\/p>\n<p>There has been a really interesting RSA <i>crypto<\/i> challenge called <i>Blind<\/i>, which I would like to share with you in this writeup.<\/p>\n<p>The article is divided into the following sections:<\/p>\n<p>\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1210#chlg\">Challenge description<\/a><br \/>\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1210#what\">What does the script do?<\/a><br \/>\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1210#blindrsa\">Blind RSA Signature<\/a><br \/>\u2192 <a href=\"https:\/\/devel0pment.de\/?p=1210#flag\">Retrieving the Flag<\/a><\/p>\n<p><!--more--><\/p>\n<hr \/>\n<h1>Blind (200 pts)<\/h1>\n<h3 id=\"chlg\">Challenge description<\/h3>\n<p>The challenge description provides the ip\/port of the CTF server running the challenge as well as a python script called <code>server.py<\/code>, which runs on the server:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1212\" src=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/03\/volga19_blind.png\" alt=\"\" width=\"597\" height=\"239\" srcset=\"https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/03\/volga19_blind.png 597w, https:\/\/devel0pment.de\/wp-content\/uploads\/2019\/03\/volga19_blind-300x120.png 300w\" sizes=\"(max-width: 597px) 100vw, 597px\" \/><\/p>\n<p>So let&#8217;s have a look at the python script:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\nfrom __future__ import print_function\nimport os\nimport sys\nimport shlex\nimport subprocess\nfrom private_key import d\n\n\n&quot;&quot;&quot;\n    Utils\n&quot;&quot;&quot;\n\n\ndef run_cmd(cmd):\n    try:\n        args = shlex.split(cmd)\n        return subprocess.check_output(args)\n    except Exception as ex:\n        return str(ex)\n\n\n&quot;&quot;&quot;\n    Signature\n&quot;&quot;&quot;\n\nclass RSA:\n    def __init__(self, e, d, n):\n        self.e = e\n        self.d = d\n        self.n = n\n\n    def sign(self, message):\n        message = int(message.encode(&#039;hex&#039;), 16)\n        return pow(message, self.d, self.n)\n\n    def verify(self, message, signature):\n        message = int(message.encode(&#039;hex&#039;), 16)\n        verify = pow(signature, self.e, self.n)\n        return message == verify\n\n\n&quot;&quot;&quot;\n\tKeys\n&quot;&quot;&quot;\n\nn = 26507591511689883990023896389022361811173033984051016489514421457013639621509962613332324662222154683066173937658495362448733162728817642341239457485221865493926211958117034923747221236176204216845182311004742474549095130306550623190917480615151093941494688906907516349433681015204941620716162038586590895058816430264415335805881575305773073358135217732591500750773744464142282514963376379623449776844046465746330691788777566563856886778143019387464133144867446731438967247646981498812182658347753229511846953659235528803754112114516623201792727787856347729085966824435377279429992530935232902223909659507613583396967\ne = 65537\n\n\n&quot;&quot;&quot;\n    Communication utils\n&quot;&quot;&quot;\n\ndef read_message():\n    return sys.stdin.readline()\n\n\ndef send_message(message):\n    sys.stdout.write(&#039;{0}\\r\\n&#039;.format(message))\n    sys.stdout.flush()\n\n\ndef eprint(*args, **kwargs):\n    print(*args, file=sys.stderr, **kwargs)\n\n\n&quot;&quot;&quot;\n    Main\n&quot;&quot;&quot;\n\ndef check_cmd_signatures(signature):\n    cmd1 = &#039;exit&#039;\n    cmd2 = &#039;leave&#039;\n    assert (signature.verify(cmd1, signature.sign(cmd1)))\n    assert (signature.verify(cmd2, signature.sign(cmd2)))\n\n\nclass SignatureException(Exception):\n    pass\n\n\nif __name__ == &#039;__main__&#039;:\n    signature = RSA(e, d, n)\n    check_cmd_signatures(signature)\n    try:\n        while True:\n            send_message(&#039;Enter your command:&#039;)\n            message = read_message().strip()\n            (sgn, cmd_exp) = message.split(&#039; &#039;, 1)\n            eprint(&#039;Accepting command {0}&#039;.format(cmd_exp))\n            eprint(&#039;Accepting command signature: {0}&#039;.format(sgn))\n\n            cmd_l = shlex.split(cmd_exp)\n            cmd = cmd_l&#x5B;0]\n            if cmd == &#039;ls&#039; or cmd == &#039;dir&#039;:\n                ret_str = run_cmd(cmd_exp)\n                send_message(ret_str)\n\n            elif cmd == &#039;cd&#039;:\n                try:\n                    sgn = int(sgn)\n                    if not signature.verify(cmd_exp, sgn):\n                        raise SignatureException(&#039;Signature verification check failed&#039;)\n                    os.chdir(cmd_l&#x5B;1])\n                    send_message(&#039;&#039;)\n                except Exception as ex:\n                    send_message(str(ex))\n\n            elif cmd == &#039;cat&#039;:\n                try:\n                    sgn = int(sgn)\n                    if not signature.verify(cmd_exp, sgn):\n                        raise SignatureException(&#039;Signature verification check failed&#039;)\n                    if len(cmd_l) == 1:\n                        raise Exception(&#039;Nothing to cat&#039;)\n                    ret_str = run_cmd(cmd_exp)\n                    send_message(ret_str)\n                except Exception as ex:\n                    send_message(str(ex))\n\n            elif cmd == &#039;sign&#039;:\n                try:\n                    send_message(&#039;Enter your command to sign:&#039;)\n                    message = read_message().strip()\n                    message = message.decode(&#039;base64&#039;)\n                    cmd_l = shlex.split(message)\n                    sign_cmd = cmd_l&#x5B;0]\n                    if sign_cmd not in &#x5B;&#039;cat&#039;, &#039;cd&#039;]:\n                        sgn = signature.sign(sign_cmd)\n                        send_message(str(sgn))\n                    else:\n                        send_message(&#039;Invalid command&#039;)\n                except Exception as ex:\n                    send_message(str(ex))\n\n            elif cmd == &#039;exit&#039; or cmd == &#039;leave&#039;:\n                sgn = int(sgn)\n                if not signature.verify(cmd_exp, sgn):\n                    raise SignatureException(&#039;Signature verification check failed&#039;)\n                break\n\n            else:\n                send_message(&#039;Unknown command {0}&#039;.format(cmd))\n                break\n\n    except SignatureException as ex:\n        send_message(str(ex))\n        eprint(str(ex))\n\n    except Exception as ex:\n        send_message(&#039;Something must have gone very, very wrong...&#039;)\n        eprint(str(ex))\n\n    finally:\n        pass\n\n<\/pre><\/div>\n\n<h3 id=\"what\">What does the script do?<\/h3>\n<p>The script reads a line from stdin and splits this line by spaces storing the first word in <code>sgn<\/code> and all following words in <code>cmd_exp<\/code>:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 88; title: ; notranslate\" title=\"\">\n            send_message(&#039;Enter your command:&#039;)\n            message = read_message().strip()\n            (sgn, cmd_exp) = message.split(&#039; &#039;, 1)\n\n<\/pre><\/div>\n\n<p>The value stored in <code>cmd_exp<\/code> is split again, this time by calling <code>shlex.split(cmd_exp)<\/code>. This function splits the given string using a shell-like syntax (<a href=\"https:\/\/docs.python.org\/3\/library\/shlex.html\" target=\"_blank\" rel=\"noopener noreferrer\">documentation shlex<\/a>). The first element of the result is stored in <code>cmd<\/code>:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 94; title: ; notranslate\" title=\"\">\n            cmd_l = shlex.split(cmd_exp)\n            cmd = cmd_l&#x5B;0]\n\n<\/pre><\/div>\n\n<p>Depending on the value of <code>cmd<\/code> one of the following if\/elif blocks is run. If <code>cmd<\/code> is <code>ls<\/code> or <code>dir<\/code>, the command stored in <code>cmd_exp<\/code> is directly executed and the result displayed:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 96; title: ; notranslate\" title=\"\">\n            if cmd == &#039;ls&#039; or cmd == &#039;dir&#039;:\n                ret_str = run_cmd(cmd_exp)\n                send_message(ret_str)\n\n<\/pre><\/div>\n\n<p>The function <code>run_cmd<\/code> calls <code>subprocess.check_output(...)<\/code> to execute the command:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 15; title: ; notranslate\" title=\"\">\ndef run_cmd(cmd):\n    try:\n        args = shlex.split(cmd)\n        return subprocess.check_output(args)\n    except Exception as ex:\n        return str(ex)\n\n<\/pre><\/div>\n\n<p>This means that we can run <code>ls<\/code> or <code>dir<\/code> without minding the value of <code>sgn<\/code> (though we must provide a value, so let&#8217;s just take <code>1<\/code> for now):<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,3]; title: ; notranslate\" title=\"\">\nroot@kali:~# nc blind.q.2019.volgactf.ru 7070\nEnter your command:\n1 ls\nflag\nprivate_key.py\nserver.py\n\n<\/pre><\/div>\n\n<p>As we can see, the <code>flag<\/code> seems to be right in front of us. We only have to run <code>cat flag<\/code>. So let&#8217;s have a look at the <code>cmd == 'cat'<\/code> elif block:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 110; title: ; notranslate\" title=\"\">\n            elif cmd == &#039;cat&#039;:\n                try:\n                    sgn = int(sgn)\n                    if not signature.verify(cmd_exp, sgn):\n                        raise SignatureException(&#039;Signature verification check failed&#039;)\n                    if len(cmd_l) == 1:\n                        raise Exception(&#039;Nothing to cat&#039;)\n                    ret_str = run_cmd(cmd_exp)\n                    send_message(ret_str)\n                except Exception as ex:\n                    send_message(str(ex))\n\n<\/pre><\/div>\n\n<p>Now the previously mentioned value of <code>sgn<\/code> comes into play. The variable is passed to the function <code>signature.verify(...)<\/code> along with the variable <code>cmd_exp<\/code>. If the function returns false (<code>not<\/code>), a <code>SignatureException<\/code> is raised and the command is not executed. In order to understand what the function <code>signature.verify(...)<\/code> does, let&#8217;s have a look at the whole <code>RSA<\/code> class:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 23; title: ; notranslate\" title=\"\">\n&quot;&quot;&quot;\n    Signature\n&quot;&quot;&quot;\n\nclass RSA:\n    def __init__(self, e, d, n):\n        self.e = e\n        self.d = d\n        self.n = n\n\n    def sign(self, message):\n        message = int(message.encode(&#039;hex&#039;), 16)\n        return pow(message, self.d, self.n)\n\n    def verify(self, message, signature):\n        message = int(message.encode(&#039;hex&#039;), 16)\n        verify = pow(signature, self.e, self.n)\n        return message == verify\n\n<\/pre><\/div>\n\n<p>As the comment above the class indicates, the class implements a simple RSA message signing. In order to sign a message, it is converted to an integer and raised to the power of <code>d<\/code> modulo <code>n<\/code>: <code>sign = message^d % n<\/code>. <code>d<\/code> is the private key we have already seen in the above output of <code>ls<\/code>, but haven&#8217;t access to (<code>from private_key import d<\/code>). To verify the signature of a message, the signature is raised to the power of <code>e<\/code> modulo <code>n<\/code> (<code>verify = sign^e % n<\/code>) and then compared to the original message. If both values match, the signature is correct (also see <a href=\"https:\/\/en.wikipedia.org\/wiki\/RSA_(cryptosystem)#Signing_messages\" target=\"_new\" rel=\"noopener noreferrer\">wikipedia<\/a>). The public key (<code>n<\/code> and <code>e<\/code>) are part of the source code and we thus know those values:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 43; title: ; notranslate\" title=\"\">\n&quot;&quot;&quot;\n\tKeys\n&quot;&quot;&quot;\n\nn = 26507591511689883990023896389022361811173033984051016489514421457013639621509962613332324662222154683066173937658495362448733162728817642341239457485221865493926211958117034923747221236176204216845182311004742474549095130306550623190917480615151093941494688906907516349433681015204941620716162038586590895058816430264415335805881575305773073358135217732591500750773744464142282514963376379623449776844046465746330691788777566563856886778143019387464133144867446731438967247646981498812182658347753229511846953659235528803754112114516623201792727787856347729085966824435377279429992530935232902223909659507613583396967\ne = 65537\n\n<\/pre><\/div>\n\n<p>What does this mean for the command <code>cat flag<\/code>, we would like to run? Well, we need the correct signature for this command. Otherwise the signature check will fail and the command is not executed. Looking a few lines ahead there actually is an elif block to sign commands:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 122; title: ; notranslate\" title=\"\">\n            elif cmd == &#039;sign&#039;:\n                try:\n                    send_message(&#039;Enter your command to sign:&#039;)\n                    message = read_message().strip()\n                    message = message.decode(&#039;base64&#039;)\n                    cmd_l = shlex.split(message)\n                    sign_cmd = cmd_l&#x5B;0]\n                    if sign_cmd not in &#x5B;&#039;cat&#039;, &#039;cd&#039;]:\n                        sgn = signature.sign(sign_cmd)\n                        send_message(str(sgn))\n                    else:\n                        send_message(&#039;Invalid command&#039;)\n                except Exception as ex:\n                    send_message(str(ex))\n\n<\/pre><\/div>\n\n<p>So we essentially can sign commands, but if the command contains <code>cat<\/code> or <code>cd<\/code>, we only get the message <code>Invalid command<\/code> (notice that the command, we want to sign, needs to be base64 encoded):<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; highlight: [1,5,7,8]; title: ; notranslate\" title=\"\">\nroot@kali:~# echo -ne &#039;cat flag&#039; | base64\nY2F0IGZsYWc=\nroot@kali:~# nc blind.q.2019.volgactf.ru 7070\nEnter your command:\n1 sign\nEnter your command to sign:\nY2F0IGZsYWc=\nInvalid command\n\n<\/pre><\/div>\n\n<p>Thus we need to find another way to sign the desired command <code>cat flag<\/code>.<\/p>\n<h3 id=\"blindrsa\">Blind RSA Signature<\/h3>\n<p>When googling for possible attack surfaces in conjunction with the challenge&#8217;s title (<code>Blind<\/code>), I always immediately stumbled upon <a href=\"https:\/\/en.wikipedia.org\/wiki\/Blind_signature#Blind_RSA_signatures\" target=\"_new\" rel=\"noopener noreferrer\">this wikipedia article<\/a> about <i>Blind RSA Signatures<\/i>. You can read the mathematical details in the article, but the idea is quite straightforward:<\/p>\n<ul>\n<li>We modify the message we want to sign based upon an additional value <code>r<\/code> (the <i>blinding factor<\/i>)<\/li>\n<li>We let the server sign the modified message (forethought: not containing &#8220;<code>cat<\/code>&#8220;)<\/li>\n<li>We use <code>r<\/code> to calculate the signature of the original message from the signature we received<\/li>\n<\/ul>\n<p>In order to understand this technique let&#8217;s have a look at a quick example.<\/p>\n<p>We choose the following values for <code>n<\/code>, <code>e<\/code> and <code>d<\/code>:<\/p>\n<pre>n = 143\ne = 23\nd = 47\n<\/pre>\n<p>Now we want to sign the message <code>7<\/code>:<\/p>\n<pre>m = 7\n<\/pre>\n<p>The signature is calculated with the following equation:<\/p>\n<pre>s = m^d % n \ns = 7^47 % 143 = 28\n<\/pre>\n<p>Thus the signature of the original message is <code>28<\/code>.<\/p>\n<p>Now let&#8217;s suppose we can&#8217;t make the server sign a message containing <code>7<\/code> (or <code>cat<\/code>), but we still want to get the signature value. In order to achieve this, we choose a blinding factor <code>r<\/code>:<\/p>\n<pre>r = 3\n<\/pre>\n<p>This value is raised to the power of <code>e<\/code> and multiplied by the original message <code>m<\/code> (modulo <code>n<\/code>):<\/p>\n<pre>m1 = m*r^e % n\nm1 = 7*3^23 % 143 = 24\n<\/pre>\n<p>Now the modified message <code>m1<\/code> does not containing the prohibited value (<code>7<\/code>) anymore. Thus we can make the server sign this message resulting in the signature <code>s1<\/code>:<\/p>\n<pre>s1 = m1^d % n\ns1 = 24^47 % 143 = 84\n<\/pre>\n<p>In order to restore the signature of the original message (<code>s<\/code>) from <code>s1<\/code> we need to multiply it by <code>r_inverse<\/code> (to calculate the inverse, we can for example use <code>gmpy for python<\/code>: <code>import gmpy; gmpy.invert(3,143) = 48<\/code>):<\/p>\n<pre>s = s1*r_inverse % n\ns = 84*48 % 143 = 28\n<\/pre>\n<p>That&#8217;s it! We successfully got the signature for the original message without the server actually signing it.<\/p>\n<h3 id=\"flag\">Retrieving the Flag<\/h3>\n<p>Before implementing this technique for our specific use case, we have to deal with a little pitfall. The message, which is signed by the server, is passed to <code>shlex.split(...)<\/code> before actually being signed:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; first-line: 125; title: ; notranslate\" title=\"\">\n...\n                    message = message.decode(&#039;base64&#039;)\n                    cmd_l = shlex.split(message)\n                    sign_cmd = cmd_l&#x5B;0]\n                    if sign_cmd not in &#x5B;&#039;cat&#039;, &#039;cd&#039;]:\n                        sgn = signature.sign(sign_cmd)\n<\/pre><\/div>\n\n<p>This means that in order to sign an arbitrary message, we have to make sure that the message is not split apart by <code>shlex.split(...)<\/code>. Otherwise only the first part of our message is signed.<\/p>\n<p>Luckily we can choose almost any value for <code>r<\/code> (it only has to fulfill the condition <code>gcd(r,n) = 1<\/code>, which is the case for quite a lot of values since <code>n<\/code>\u00a0is the product of two big primes).<\/p>\n<p>In order to find a suitable value for <code>r<\/code> I wrote the following python script, which simply iterates over different values for <code>r<\/code> and checks if the modified message and the return value of a call <code>shlex.split(...)<\/code> are the same:<\/p>\n<p><code><code><code><\/code><\/code><\/code><\/p>\n<p><code><code><\/code><\/code><\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nimport shlex\n\nn = 26507591511689883990023896389022361811173033984051016489514421457013639621509962613332324662222154683066173937658495362448733162728817642341239457485221865493926211958117034923747221236176204216845182311004742474549095130306550623190917480615151093941494688906907516349433681015204941620716162038586590895058816430264415335805881575305773073358135217732591500750773744464142282514963376379623449776844046465746330691788777566563856886778143019387464133144867446731438967247646981498812182658347753229511846953659235528803754112114516623201792727787856347729085966824435377279429992530935232902223909659507613583396967\ne = 65537\n\nm = int(&#039;cat flag&#039;.encode(&#039;hex&#039;), 16)\n\nr = 1\n\nwhile True:\n  m1 = (m*r**e)%n\n  m1 = hex(m1)&#x5B;2:-1] # cut leading &#039;0x&#039; and trailing &#039;L&#039;\n  if (len(m1)%2 == 1): m1 = &#039;0&#039; + m1 # adjust padding\n  m1 = m1.decode(&#039;hex&#039;)\n\n  try:\n    res = shlex.split(m1)&#x5B;0]\n  except: pass\n  if (res == m1):\n    print(&#039;r = &#039; + str(r))\n    quit()\n\n  r += 1\n\n<\/pre><\/div>\n\n<p>Running the script yields <code>r = 6631<\/code> as a suitable value:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~# .\/getBlindingFactor.py\nr = 6631\n\n<\/pre><\/div>\n\n<p>At last we can implement the final script to retrieve the flag. I annotated the source code with comments, which hopefully makes things clear:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: python; title: ; notranslate\" title=\"\">\n#!\/usr\/bin\/env python\n\nfrom pwn import *\nimport gmpy\n\nn = 26507591511689883990023896389022361811173033984051016489514421457013639621509962613332324662222154683066173937658495362448733162728817642341239457485221865493926211958117034923747221236176204216845182311004742474549095130306550623190917480615151093941494688906907516349433681015204941620716162038586590895058816430264415335805881575305773073358135217732591500750773744464142282514963376379623449776844046465746330691788777566563856886778143019387464133144867446731438967247646981498812182658347753229511846953659235528803754112114516623201792727787856347729085966824435377279429992530935232902223909659507613583396967\ne = 65537\n\nm = int(&#039;cat flag&#039;.encode(&#039;hex&#039;), 16)\n\n# suitable blinding factor\nr = 6631\n\n# calculate modified message m1\nm1 = (m*r**e)%n\nm1 = hex(m1)&#x5B;2:] # cut leading &#039;0x&#039;\nif (len(m1)%2 == 1): m1 = &#039;0&#039; + m1 # adjust padding\nm1 = m1.decode(&#039;hex&#039;).encode(&#039;base64&#039;).replace(&#039;\\n&#039;,&#039;&#039;) # encode\n\n# connect to ctf server\np = remote(&#039;blind.q.2019.volgactf.ru&#039;, 7070)\np.recvuntil(&#039;Enter your command&#039;)\n\n# sign modified message m1\np.sendline(&#039;1 sign&#039;)\np.recvuntil(&#039;Enter your command to sign:&#039;)\np.sendline(m1)\n\n# receive signature s1\np.recvline()\nresp = p.recvline()\ns1 = int(resp)\n\n# calculate signature s from s1 and r\ns = s1*int(gmpy.invert(r,n))%n\n\n# send command &#039;cat flag&#039; with appropriate signature\np.sendline(str(s) + &#039; cat flag&#039;)\np.interactive()\n\n<\/pre><\/div>\n\n<p>Running the script yields the flag:<\/p>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nroot@kali:~# .\/catFlag.py\n&#x5B;+] Opening connection to blind.q.2019.volgactf.ru on port 7070: Done\n&#x5B;*] Switching to interactive mode\nEnter your command:\nVolgaCTF{B1ind_y0ur_tru3_int3nti0n5}\n\n<\/pre><\/div>\n\n<p>The flag is <code><span class=\"spanFlag\">VolgaCTF{B1ind_y0ur_tru3_int3nti0n5}<\/span><\/code>.<\/p>\n<p>Thanks for reading the article \ud83d\ude42<\/p>","protected":false},"excerpt":{"rendered":"<p>The VolgaCTF 2019 Qualifier (ctftime.org) took place from 29\/03\/2019, 15:00 UTC to 31\/03\/2019 15:00 UTC. There has been a really interesting RSA crypto challenge called Blind, which I would like to share with you in this writeup. The article is divided into the following sections: \u2192 Challenge description\u2192 What does the script do?\u2192 Blind RSA &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/devel0pment.de\/?p=1210\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;VolgaCTF 2019 Qualifier &#8211; Blind&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24,7],"tags":[23,38,37],"class_list":["post-1210","post","type-post","status-publish","format-standard","hentry","category-ctf","category-writeup","tag-crypto","tag-python","tag-rsa"],"_links":{"self":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1210"}],"collection":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1210"}],"version-history":[{"count":19,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1210\/revisions"}],"predecessor-version":[{"id":1231,"href":"https:\/\/devel0pment.de\/index.php?rest_route=\/wp\/v2\/posts\/1210\/revisions\/1231"}],"wp:attachment":[{"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1210"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1210"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devel0pment.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1210"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}