This article is part 9 of a 10 series blog detailing the approaches and solutions to hacking through Stripe’s 2012 CTF 2.0. To continue from the parent article, or see more hacks, please click here.
This blog entry details the approach used by Andre Azzolini in attacking the Stripe CTF 2.0 Challenge Level 8.
The final level, 8, required you to send a password guess to a server, which then replied whether or not you were successful. Examining the code showed that the password was 12 numerical digits long, which is 10^12 complexity — obviously not something that can be easily brute forced.
Fortunately for us, the password is broken up and stored across four different servers in chunks of three, with a primary server being the interface we use to guess the password. This immediately hints that we need to brute force the password a chunk a time, which reduces the password complexity down to a doable 4 * 10^3. The trick then, is figuring out how to talk to a chunk server individually.
Stripe provides you with some extra knowledge for this level: someone left sshd running on the level 2 boxes. So, let’s gain access to level 2!
$ ssh -v email@example.com
ssh debug1: Authentications that can continue: public key
So, only public key authentication is allowed. Fortunately, we have already learned how to execute code on the box, so we simply need to copy a public key for which we know the private key to the Unix standard ~/.ssh/authorized_keys file.
mkdir("/mount/home/user-aiwdhvxggh/.ssh", 0777); $myFile = "/mount/home/user-aiwdhvxggh/.ssh/authorized_keys"; $fh = fopen($myFile, 'w') or die("can't open file"); $stringData = ""; fwrite($fh, $stringData); fclose($fh);
Upload that to level 2, and you can now SSH using our easy SSH Authentication bypass hack.
Now that we have shell access, we can attempt to communicate to the level 8 chunk servers. To be more specific, we are able to try to force the level 8 servers to talk to us on a high port, since we know that they are not firewalled off. We see from the level 8 code that there is a webhook that we can pass to the primary server when attempting to authenticate that will tell the level 8 server to also establish a connection to that webhook and tell it whether or not we were successful.
So, we can open a socket on level 2 and listen for the webhook. Unfortunately, we don’t learn any additional information by looking at the contents of the response. We do, however, see the foreign port that the connection came from. Because Unix allocates ports for sockets from a pool that increases incrementally, we start to see a pattern related to the ephemeral ports problem. When the first chunk is correct, the primary server makes one additional request to the second chunk server to verify the second chunk. We can do basic math to determine the number of connections the primary server attempted to make and use that to determine whether a given chunk was successful or not.
Since many people were trying at the same time, we came up with false positives reasonably often. However, some verification logic helped us narrow down the correct chunk, one at a time. All in all, it took about 45 minutes to brute force the password. We could have likely done this faster implementing other techniques such as HTTP pipelining and keeping a permanently open socket to make requests with, but 45 minutes was not a bad wait.
Let’s clarify with a quick example of how the brute force algorithm works, since there are a few nuances.
- Make a connection to the primary server with a bad guess (say, 12 zeroes) and record the port number. Pretend it was 50000
- Make a connection to the primary server with a possible guess (001000000000) and record the port number. Say it was 50003.
- The difference in ports was 3. So now, we can test it with another guess, 002000000000. If the port difference is also 3, we know that it didn’t have to talk to second chunk server, which means that it failed after the first chunk and we can move on.
- However, if the port difference was 4, we know the primary server had to make one extra connection and that we have our chunk.
- Rinse and repeat for the next two chunks, and then make actual guesses to the primary server with the full four chunks, and there you have it!
Hungry for more Stripe CTF? Check out our Bonus Section!
These solutions are presented as a unique approach to a recent CTF hacking contest as an outreach of the Credera Security Team. All ‘hacking’ was performed in an ethical manner in accordance with Credera’s Core Values. For further information on Credera’s offerings in ethical hacking, security, compliance, and OWASP preparedness please contact us at firstname.lastname@example.org