This was a fun challenge because I got to use hash extension attack. To learn about hash extension attacks, Ron Bowes has a great blog post about hash extension attacks and a corresponding GitHub repository of the hash_extender tool which I used directly in my solution to this challenge.
For Viettel Store, I was given a file crypto1.py and nc 13.251.110.215 10001
.
crypto1.py
1 | import time |
The general flow of the program seems simple enough. I’m given some random amount of money and can “order” an item, in which the URL parameters containing the product, price, and a timestamp (in nanosecond time) is hashed via sha256 after being prepended with a secret signing key of some random length between 8 and 32. I can then use this output to pay for the item. The menu item checks that the hash is the same and that I have enough money to purchase the item. The code shows obviously that I need to somehow purchase the item FLAG
in order to get the flag for the challenge. The following shows some sample usage.
1 | $ nc 13.251.110.215 10001 |
The main problem seems to be that the price of the item FLAG
is far too high – and my starting money is determined via random.randint(1000000, 5000000)
. The crypto part of the challenge comes from the code taking everything before &sign
, prepending it with a secret signing key, and then calculating the sha256 hash. It turns out that this exact circumstance is vulnerable to a hash extension attack. I can use the tool hash_extender called via python’s Popen
in order to calculate a new possible hash without knowing the secret signing key AND I can append arbitrary data to the end as well. This is perfect because I want to append &price=1
to the end of the URL parameter list so that FLAG
is affordable. This will work out since the for-loop using parse_qsl
will overwrite previous parameters.
To clarify, I can give hash_extender prior knowledge such as product=FLAG&price=999999999×tamp=1529219946064768
hashing to 061d90bd351d5b994b9b5ecf4b84928563aa0449dc30f510d8f42d04a391fa59
and tell it that I want to append &price=1
to the end of the string to give me a new hash. This new hash can be used to then buy the FLAG
item. Easy!
I want to use hash extender in the following way:
1 | $ ./hash_extender -d <originally hashed url string> --signature=<sha256 hash of url string> --format=sha256 --secret-min=8 --secret-max=31 --append=&price=1 --append-format=html --data-format=cstr --out-data-format=hex |
This gives many lines of output of input strings corresponding to the resulting hash that we can use to trick the validation logic in crypto1.py. The following script is my solution to this ctf challenge where I use hash_extender to give me a list of new hashes and their corresponding url strings.
crypto1sol.py
1 | import time |
Running the script will do all of this for me and give the flag (sometimes after many tries due to unknown length of secret signing key):
1 | $ python crypto1sol.py |
The flag for this challenge is: matesctf{e4sy_3xt3nti0n_4tt4cK_x0x0}
.