304 North Cardinal St.
Dorchester Center, MA 02124

Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM

Custom Cryptography + OSINT (EverSec CTF @ BSidesRDU)

There was an OSINT + custom cryptography challenge during the BSidesRDU CTF this year, but no one (else) was able to solve it from start to finish.

Custom Cryptography – Introduction

First, Steve’s challenge mentioned some chatter on Twitter.

Custom Cryptography - Challenge

While most of this challenge was Open-source intelligence (OSINT) based, I’m most proud of my crypto solution.

Initial OSINT

First, I checked out the EverSec Twitter account.

There was nothing there, so I decided to search Twitter for EverSec in general.

This brought me to the r3tsuk0_ timeline, and the following tweets.

Custom Cryptography - Tweets

While custom cryptography sounded interesting, there was still another flag or two on the OSINT side.

To Understand the Future, We Have to Go Back in Time

After some prodding and asking for clues, the r3tsuk0_ account made another tweet.

Custom Cryptography - Username Change

While Google was no use, I did have some luck with the Wayback Machine.

Custom Cryptography - Archive

When I searched for the archived pages under that URL, there was one result.

Custom Cryptography - Results

Viewing the deleted tweet gave me another flag, and a pretty cool challenge!

Custom Cryptography - Deleted Tweet

GitHub Profile, and More Flags!

With the Twitter part of the OSINT challenge completed, I moved on to the cryptography part.

First, I used some professional Google skills (removing the underscore from the username) to find r3tsuk0’s GitHub profile.

The only repository on the account was encrypt, so this was likely the custom cryptography challenge.

Note that there was a reverted commit that had one more flag in it.

output = ""
for letter in x:
	o = int(ord(letter))
	o += 2
	output = output+str(o)+"23"
	output = output[::-1]

Breaking the Cipher

First, I grabbed the encryption routine, and took a look at it.

output = ""
for letter in x:
    o = int(ord(letter))
    o += 2
    output = output+str(o)+"23"
    output = output[::-1]

While this is fairly straightforward, I will break down the encryption step by step.

  1. Grab the next character from the input string
  2. Convert the character to an ordinal, and then an integer. For example: ord(‘a’) = 97, and then o gets cast to an integer.
  3. Add 2 to the converted value
  4. Append the string variant of the new value, concatenated with the string “23”, to the output string
  5. Reverse the entire output string
  6. Loop back to step #1 until the string is finished

Taking a look back through the Twitter timeline, I guessed that the “32053241132611327932911327932011326115023110231172311123101231232311823” value would be the input string.

In this case, the output string calculation would look like this through the first loop:

  1. output = “” – no characters added yet
  2. o = 51 – int(ord(“3”))
  3. o = 53 – o += 2
  4. output = “” + “53” + 23″
  5. output = “5323” – concatenation
  6. output = “3235” – reverse

With this in mind, I knew that the difficulty would be when the string reverses. While most characters would cause the cipher to store a 2-digit number in ‘o’, some could cause a 3-digit number.

>>> int(ord("z"))

This may not have mattered for this specific input, but I wanted to solve for any if it came up again.

My Solution

In this case, I designed a fairly elegant solution, that didn’t take much actual cryptanalysis.

import string

input = "32053241132611327932911327932011326115023110231172311123101231232311823"
output = ""

curString = input

while (len(curString) > 0):
    curString = curString[::-1]
    charCheck1 = curString[-4:-2]
    charCheck2 = curString[-5:-2]
    charCheck1 = int(charCheck1) - 2
    charCheck2 = int(charCheck2) - 2
    if (chr(charCheck2) in string.printable):
        curString = curString[:-5]
        output = chr(charCheck2) + output
    elif (chr(charCheck1) in string.printable):
        curString = curString[:-4]
        output = chr(charCheck1) + output

In the end, this reverses the entire encryption algorithm from before, with a quick brute-force step to account for the warning above.

If you are not familiar with Python, then I will break down the steps for you.

  1. Take the input string, and store it in a temporary variable
  2. Reverse the entire string
  3. Grab the last 2 characters of the string, ignoring the “23”, and store them in charCheck1
  4. Grab the last 3 characters of the string, ignoring the “23”, and store them in charCheck2
  5. Subtract 2 from charCheck1
  6. Subtract 2 from charCheck2
  7. If charCheck2 (the 3-digit string) is printable, then append it to the output string
  8. If not, and charCheck1 is printable, then append it to the output string
  9. If neither is printable, then there was likely a problem with the input
  10. Loop until there is nothing left in curString

As far as the brute-force step, this is really where my solution is elegant. In the case where the input was only a 2-digit ascii character, then grabbing three characters ends up with a 2xx or a 3xx, due to the cipher concatenating with “23”. There are no printable characters in the 200-399 range, so we can safely assume that a 2-digit solution is safe here.

When I ran my finished script, I received the last flag!

PS C:\Users\Ray\Documents> py .\

Custom Cryptography – Conclusion

While most of this challenge was the OSINT, I really liked the crypto solution.

This was a bit heavier on the programming, rather than crypto, side in the end, which is likely why no one solved it completely.

That said, I was glad that Steve pointed this one out, and I had some fun with it.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.