The third puzzle I solved was the challenge DNAdecay
Our flightless birds can run upto 50km/h but we want them to go faster. I've been messing with a mutigen but it seems to have corrupted. Can you help me recover this research?
Author: BootlegSorcery@
For this challenge we are given a Ruby file that references a library called "doublehelix" and text that looks like a strand of DNA. A quick scan shows that for some of the strands of DNA, one or both letters are missing, hence the corruption referenced in the description.
DNA is comprised of two strands of nucleotide chains where a nucleotide on one strand is connected not only to the previous and next item in its own chain but to its corollary in the other strand.
There are 4 nucleotides: adenine (A), cytosine (C), guanine (G), and thymine (T). Adenine and thymine only bond together across strands and the same with cytosine and guanine. So, if you only have one strand of DNA, you can determine what the missing side looks like. This will become important soon.
Let's take a subsection of the doublehelix to see what we're facing
T -
T -
CG
C
G -C
G---C
G - C
G ---
---
---T
- A
In analyzing the lines, we have 4 types of information.
Both letters which will be in order
One letter but we have dashes to help us know which side it's on
One letter with no strand information
No letters
A quick look at the doublehelix Ruby library and some testing also gives us this information:
The spaces are decorative
The dashes when both letters are present are also decorative
We can't run the ruby until we have at least placeholders in place for everything so let's figure out how to approach that.
Trying to look through this as originally presented is rather noisy. So the first thing I did was in my text editor, I created a regex that would allow me to make clear which lines didn't need work.
The way I decided to approach this is to find the lines with two letters, and strip out all spaces and dashes, thus moving the two letters to the left and leaving the ones that needed more work mostly to the right.
I used BBEdit and did a grep based find and replace with this regex ^ *(\w)[ -]*(\w) *$.
The next step is to fill in the ones where we have one character and we know which side of the helix it is on. There is a total of 8 combinations we have to think through here.
^[ -]+- *C *$
^[ -]+- *G *$
^[ -]+- *A *$
^[ -]+- *T *$
^ *(C) *-[ -]+ *$
^ *(G) *-[ -]+ *$
^ *(A) *-[ -]+ *$
^ *(T) *-[ -]+ *$
Step 3: Take guesses on the remaining ones
After all that work we are left with the following.
TA
TA
CG
C
GC
GC
GC
GC
---
AT
TA
As you can probably see, the ones that still need work are much easier to see. I actually added spaces to make them easier to see because in some cases they were to the left hand side.
All I did at this point was make some guesses because once we're sure that we have 2 characters on each line, we're ready to run the Ruby code.
So far I've been basing this approach about what I know about DNA, but it's probably worth taking a look at the code itself.
$code = ""
Object.instance_eval do
def const_missing(s); $code << s.to_s; 0; end
remove_const(:GC) # Holy moly!
end
at_exit do
dict = { "AT"=>"00", "CG"=>"01", "GC"=>"10", "TA"=>"11" }
eval([$code.gsub(/../) {|s| dict[s] }].pack("b*"))
end
def doublehelix(src)
dict = { "00"=>["A","T"], "01"=>["C","G"], "10"=>["G","C"], "11"=>["T","A"] }
format = [[1,0], [0,2], [0,3], [0,4], [1,4], [2,4], [3,3], [4,2], [5,0]]
format += format.reverse
%(require "doublehelix"\n\n) + src.unpack("b*").first.gsub(/../) do |s|
format << (offset, dist = format.shift)
" " * offset + dict[s] * ("-" * dist) + "\n"
end
end
I actually can't go too deep into all of it because I don't know Ruby all that well, but the important part for us is here: dict = { "AT"=>"00", "CG"=>"01", "GC"=>"10", "TA"=>"11" }
Essentially, for each pair it finds, it will substitute in those digits. Put together 4 pairs and you have the bytes for one ascii character.
So with the random substitutions where we didn't have enough information, here's what I get when I run it and get.
/Library/Ruby/Gems/2.6.0/gems/doublehelix-1.0/lib/doublehelix.rb:8:in `eval': (eval):1: unterminated string meets end of file (SyntaxError)
...15ohe_P0wFrSH�UpF_cfODA_�3LL}.
Ok, so something is happening! But first, it looks like the string needs an end quote.
For that one, I can see the last group of 4 had just one where we had to guess. The original had a T with no direction info. I had made it a TA and switching it to an AT got rid of the error.
D�CTF{4H_�it0k�OngRi4�15ohe_P0wFrSH�UpF_cfODA_�3LL}
Now that I'm fairly confident that the change is what we want, I can move those letters to the left to reflect that confidence.
So the next thing I can do is break up the lines into 4 line groups and each of those groups will represent one letter in the output.
I started working from the end to the beginning because I wasn't quite sure what the command being run was at the start to get it to print out.
While there is another letter that we made some guesses at, it's clear that the character right before the 3 is not right, so let's play with that. I had guessed:
TA
AT
AT
CG
Let's try some other guesses to get something interesting. I swap in GC and now we get the letter C, making it:
D�CTF{4H_�it0k�OngRi4�15ohe_P0wFrSH�UpF_cfODA_C3LL}
Well, that sure looks like a word. I see a few other possible words in there like maybe the word power. At this point, it's just a rinse and repeat until we can find the right combination in those questionable areas to get us something usable.
I kept fiddling around with these until eventually I got DUCTF{7H3_Mit0cHOndRi4_15_7he_P0wEr_HoUsE_of_DA_C3LL} which makes sense in terms of the clue.