title: Juniors CTF 2016 - Web500 Crypto-shop Write Up
author: depierre
published: 2016-11-27
categories: CTF, Security
keywords: juniors, ctf, write-up, web, 500, challenge, rsa, cookie
I played the Juniors CTF 2016 this weekend with some friends of mine and it was quite fun! Since we missed the
registration deadline, I sneakily joined the [Securimag](https://securimag.org/wp/) team and played with them.

Among the different web challenges that we solved, [@xarkes](https://twitter.com/xarkes_) and I thought that
Crypto-shop was one of the most interesting challs from the web category.
# Crypto-shop
Accessing the web application, we are greated with a wonderful Russian web page:

Basically it says that the file we want to buy is worth `140.3` gravitycoins, that our `wallet` is
`32ca4862166b08c72787f4bf258cc2f09` and that our current balance is `0` gravitycoin. We supposed that we had to find a
way to buy a gravitycoin in order to get the flag.
# Cooooookies
Using [Burp](https://portswigger.net/burp/), we see that when accessing the homepage:
:::http
GET /index.php HTTP/1.1
Host: 10.0.192.235:61741
Two cookies are generated:
:::http hl_lines="5 6"
HTTP/1.1 200 OK
Date: Sat, 26 Nov 2016 19:50:51 GMT
Server: Apache/2.2.22 (Debian)
X-Powered-By: PHP/5.4.45-0+deb7u5
Set-Cookie: gravitycoin=ga8c%2B5oOnlS%2B26EiReR%2Bh3y4HV0ArWvxYgYESCn7BLSpvL8pIZRc2Bsdd6lnXu%2BNk7app4QgamoAkoqW4zJCQA%3D%3D; expires=Tue, 06-Dec-2016 19:50:51 GMT; path=/
Set-Cookie: wallet=7b693c3fef8c70db769a8c665cde55ca; expires=Tue, 06-Dec-2016 19:50:51 GMT; path=/
Vary: Accept-Encoding
Content-Length: 2837
Connection: close
Content-Type: text/html
The `wallet` cookie is our wallet ID, shown on the home page but what is that `gravitycoin` wallet? It's a base64
encoded value that doesn't decode to anything meaningful so we assumed that it was encrypted. Could it be some kind of
[padding oracle attack](https://en.wikipedia.org/wiki/Padding_oracle_attack)?
When we modify one byte of the `gravitycoin` value, the application says "Current balance: incorrect value" (translated
from Russian). Except from a reflected XSS in the `wallet` cookie, we couldn't find anything helpful at that time.
# RSA public key
Trying to find more information to work with, we found that the web application had a `robots.txt` file:
:::http
GET /robots.txt HTTP/1.1
Host: 10.0.192.235:61741
Listing some potentially interesting files maybe?
:::http hl_lines="14"
HTTP/1.1 200 OK
Date: Sat, 26 Nov 2016 18:11:42 GMT
Server: Apache/2.2.22 (Debian)
Last-Modified: Wed, 23 Nov 2016 13:27:38 GMT
Accept-Ranges: bytes
Content-Length: 79
Vary: Accept-Encoding
Connection: close
Content-Type: text/plain
User-agent: *
Disallow: /index.html
Disallow: /index.php
Disallow: /rsa.html
Let's check `rsa.html`:
:::http
GET /rsa.html HTTP/1.1
Host: 10.0.192.235:61741
It might be what we are looking for:
:::http hl_lines="17 18 19 20"
HTTP/1.1 200 OK
Date: Sat, 26 Nov 2016 18:11:45 GMT
Server: Apache/2.2.22 (Debian)
Last-Modified: Wed, 23 Nov 2016 13:27:38 GMT
Accept-Ranges: bytes
Content-Length: 303
Vary: Accept-Encoding
Connection: close
Content-Type: text/html
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMUxrqFZ5appjJI7Yf8TDVpy3ITYzh9s
CTflAdameod0AtdQ5QCAVCpFi1ZLe5ZvwNwIlsEdTDEqfi2CH8Ylf9cCAwEAAQ==
-----END PUBLIC KEY-----
It contains a public RSA key, interesting. Oh Sneaky bastards! If you try to access the resource from your web browser,
you would be redirected to `403.html`, which tells you that the access is denied. Hopefully we didn't waste time on
that one since Burp doesn't care about the JavaScript.
# RSA? What for?
Now that we got a RSA public key, what could we do with it? We thought that we could maybe factorize the key and
decrypt the `gravitycoin` cookie value:
:::bash hl_lines="2"
depierre$ openssl rsa -inform PEM -pubin -in key.pub -noout -text
Public-Key: (512 bit)
Modulus:
00:c5:31:ae:a1:59:e5:aa:69:8c:92:3b:61:ff:13:
0d:5a:72:dc:84:d8:ce:1f:6c:09:37:e5:01:d6:a6:
7a:87:74:02:d7:50:e5:00:80:54:2a:45:8b:56:4b:
7b:96:6f:c0:dc:08:96:c1:1d:4c:31:2a:7e:2d:82:
1f:c6:25:7f:d7
Exponent: 65537 (0x10001)
512bit? Hum, maybe it can be factorized after all... We used different tools such as
[Cryptool](https://www.cryptool.org/en/ct1-downloads) and [YAFU](https://github.com/DarkenCode/yafu) but after running
for a couple of hours, they still didn't yield any results so we gave up factorizing the key and moved on.
In brief:
+ We have an encrypted cookie, likely containing information about our wallet and our balance
+ A RSA public key
# Encrypt your own
What if, instead of finding the private key to decrypt our cookie, we forge our own `gravitycoin` cookie and encrypt it
using the public RSA key we found?
One problem is that we don't know the format of the cookie but maybe we could guess it? Afterall, there are not that
many parameters: the md5 hash for the wallet and 0 (our balance).
Since you can't encrypt strings longer than 53 bytes with the short RSA public key we found, we brainstormed for a
minute to come up with potential formats the cookie could use so we could bulk-generate and bulk-encrypt cookies. Below
is an extract of the potential formats we came up with:
:::bash
### Placeholders to replace later
# w: wallet; W: md5
# g: gravitycoin; G: 0
###
w=W&g=G
g=G&w=W
w:W&g:G
g:G&w:W
...
{W:G}
{G:W}
...
2|1:G|W
2|32:W|1:G
2|1:G|32:W
...
G
g:G
g=G
"g":G
'g':'G'
In total, we generated 75 different cookies and tried all of them using Burp:

And the winner format is.......... `G`... We spent 30 minutes to come up with different formats and the correct one is
of course the simplest (and also one of the last one we guessed).
We then generated a `gravitycoin` cookie with a value greater than 140.3:
:::bash
depierre$ echo -n '200' | openssl rsautl -encrypt -pubin -inkey key.pub | base64
jfxAOXheApfGd+C2AWaEIZJc/Lh65W1GFlLYG3hgyT4oTFifE3nzsw9QDOsu7FPiASU/JQwRVX1K
0EayJ8gy1A==
And bought the sh\*t out of that file!
:::http hl_lines="3"
POST /index.php HTTP/1.1
Host: 10.0.192.235:61741
Cookie: gravitycoin=jfxAOXheApfGd%2bC2AWaEIZJc/Lh65W1GFlLYG3hgyT4oTFifE3nzsw9QDOsu7FPiASU/JQwRVX1K0EayJ8gy1A%3d%3d; wallet=eb78b1c0d1d6259d5e1ac7f919ba8bba;
Content-Length: 0
Granting us what we were looking for:
:::http hl_lines="12"
HTTP/1.1 200 OK
Date: Sat, 26 Nov 2016 21:20:27 GMT
Server: Apache/2.2.22 (Debian)
X-Powered-By: PHP/5.4.45-0+deb7u5
Accept-Ranges: bytes
Content-Length: 40
Content-Disposition: attachment; filename=b42e6n7o3f3f1c0m82oj3lg6zg5w7
Set-Cookie: gravitycoin=QeDhqsD5KMrWgiFT7WdWgyLsw1Wujhi8S3kAUZI03aSp33wlKvqcq8W5BCRQmmlcY7x%2F2998r%2BGejAmlUZf17w%3D%3D; expires=Tue, 06-Dec-2016 21:20:27 GMT; path=/
Connection: close
Content-Type: application/octet-stream
Stan_creator_6fsd%hjaB56_gravitycoins
Flag: **Stan_creator_6fsd%hjaB56_gravitycoins**

By the end of the CTF, we solved quite a lot of challenges and reached the 5th place :)