DSICTS CTF Writeup (Capture The Flag Answers)

Technology October 17, 2019
This is the write-up or the answers for Sri Lanka's first-ever Capture the Flag Hacking competition organized by a school. Organized by the ICT society of D.S.Senanayake College Colombo 07 this event was held on the 25th of October 2019 with the participation of many popular school teams. Each team consisted of 5 members & their skill in the cyber security field was tested to the limit. I designed this CTF challenge and also another event that was also a first in Sri Lanka by a school: the Inter School Competitive programming challenge; it was in the format of the International Olympiad in Informatics or IOI.

This CTF challenge consisted of 3 levels. Them being Easy, Medium and Hard. They consisted of a wide variety of cyber security scenarios such as

  • Steganography
  • Cryptography
  • Wireless
  • SQLi and etc.
You can view and try your level in this CTF before viewing the answers.
The CTF challenge can be found at this link


To view the writeup for the medium level click here

To view the writeup for the medium level bonus round click here



The landing page for the CTF hard level was

Hard Landing Page



Hard - Challenge 20 - "'Krack' it people!!"




This challenge gives us a flag.zip file and asks us to crack it.

So let's crack it.
We can use any tool such as "fcrackzip" to do this
Also since many CTFs use rockyou.txt because it is an defaulty included in Kali Linux let's use it as the wordlist
So after a while we can find out that the password is "israelteamo"
We can open the zip to find out the txt file which contains the flag

DSICTS{israelteamo}



Hard - Challenge 21 - "Did you recognize me??"




This challenge is designed to bring the contestents to ground level after spending so much time in the Sky Level trying advanced hacking techniques
for example I spotted a contestant using SQL injection against a challenge when the password and the username was simply hidden on the web page by the css white color tag.(easy cahllenge 01)

Answer is simple
It is the letters in the image
So we will get

dsicts{asdljhasduu8d7981*9()-asd=-0=-0asd)_+sdas)dashbjcdljbh*7dasbas89d*(&agaleliolksjdl;knkljsadsl;kmasdmahanaskdajas77&s}


Hard - Challenge 22 - "Serious Transmissions!"



This challenge is somewhat hard. This was inspired by a recent CTF challenge.
And only 20 teams out of 1378 teams solved this.
So good luck to those who tried this.

The challenge tells us..

"Our radio team has intercepted a seemingly weird transmission transmitting from an
unidentified radio station located in North Pole. Please decode it for us, it seems important"
	
						

and it give us this audio file



When we play this, a male voice greets us but we can't understand a thing that he says. So let's get into it.
We have to reverse the audio in order to find the next clue.
The reversed audio file is given below

Transcribing this audio will give..

"Dear CTF player, Welcome to D S I C T S hacking challenge HARD level. you have exploited using
 SQLi, deciphered dank horse cryptography, hacked your way into WPS protected WIFI and done some
forensic analysis with Googal, now another challenge awaits.

The evil Grinch is holding Santa hostage in an undisclosed location, we don't know his exact
position.

A nice elf has told us the coordinates of nearby points.

The first one is located at
(511716656388765455430016138955706839007890052532 . comma .
1622805609316535864254436412730925222158623332074)

The second one is at
(390390142500834541752332649936545354218395003257 . comma .
176460719206642987153469086794475382972064519404)

And the last one is at
(608097554835704767294367078594102923662585120876 . comma .
195121033653477539025103641752423493583135321761)

He also told us that Santa's home will be located, where the shape formed by these three
points is in complete equilibrium.

Good luck and Happy Hunting.
And also enjoy the DSICTS hacking challenge. We hope that you win."

Plotting those coordinates to world’s map will give us nothing and just a clear rabbit hole
If you request a hint it will tell you that this is a geometry challenge
So get on Google and search for formulas related to Geometry
You will find analytic Geometry’s formula in calculating the centroid, mainly because it uses the given coordinates of the three vertices of a triangle
You can also find this "centroid" in the Local A/L combined Maths syllabus in 'co-ordinate geometry'

centroid = ((x1 + x2 + x3)/3, (y1 + y2 + y3)/3);
	

We can use the following formula to find the centroid of the given co-ordinates from the audio

x1 = 511716656388765455430016138955706839007890052532
x2 = 390390142500834541752332649936545354218395003257
x3 = 608097554835704767294367078594102923662585120876
y1 = 1622805609316535864254436412730925222158623332074
y2 = 176460719206642987153469086794475382972064519404
y3 = 195121033653477539025103641752423493583135321761

centroid = ((x1 + x2 + x3)/3, (y1 + y2 + y3)/3);
The result is 
(503401451241768254825571955828785038962956725555, 664795787392218796811003047092608032904607724413)

	

The value of centroid above is in decimal format (base 10) and we have to convert it to HEX (base 16) and convert it to ASCII to get the flag.

Flag: X-MAS{An4ly71c_G30m3try_S4v3d_Chr157m4s}
	
							

Hard - Challenge 23 - "Hybrid Pads"

The challenge tells us..


"One member of our CTF team made a unforgivable mistake using multi time pad.
He definitely knew that the OTP if it was well applied is unbreakable.
But this brainless retard went nuts. Not only that, he deleted the original plain text.
So now we are screwed.
The only thing remaining is the following file: cipher.json
It contains multiple cipher text that was created using OTP and the same key
So can you figure out the plain text of the cipher_flag ?"
	
	

This is a cryptography challenge about one-time pad (OTP). OTP is said to be uncrackable as long as you keep the messages short, use shorthand and abbreviations, remove unnecessary letters, never reuse a pad, and have a good enough random source for data. The challenge gives us a "cipher.json" file which contains 11 instances of cipher_list and a cipher_flag all in hex format.

{
	"cipher_list": [
		"1b0605000e14000d1b524802190b410700170e10054c11480807001806004e4f1f4f01480d411400531158141e1c100016535a480c000c031a000a160d421e004113010f13451e0c0100100a020a1a4e165f500d0c1e041a090b001d0515521c0a0410000a4f4b4d1d1c184d071600071c0a521d1706540940",
		"1e10524e001f11481c010010070b13024f0704590903094d0c000e4f0711000615001911454217161a1a45040149000a5218404f1e0012060b1b590a1048171741140c01174c0d49174f0c8d4fc7520211531b0b0c1e4f",
		"1d0c04451352001a000154431b014109450a0a0b000045490403520a1d16490008535848085942071c0d0c57101c0045111c40430c4e111c0b1b1c451d4f071712010508475518061d00060a1b0a1a4c165d",
		"160d074300061d071b524e06190b134e450a0b0a4d4c12411d004f014045491b4649074804001100011d4504520612451e165d53064e164e1d060d0d44541a0041031b0b06540d1a070004001d4b074800531c04101d4f",
		"1a1d524912521548120045021b4e1506490a0859150345531d12521b4e094909030003011148420453074d161e05540b071e4c451b000a084a1d1c04084c0b45060b060a4742070618534218070210484512020043100e191e5956111a1c001c1f0b5c",
		"1a1d5248000154041a1c47430d0b04000005015900140c4f04534f094e08490103000000045442111b11001b1b1d000917535a48004e021d4a0e0b0044491c03080a001a024c11490748074f02040054451a1d150c1b150d020d0e",
		"1a1d5249125215481613500a1b0f0d4e4d0d1c0d000700001d1c001b06004f1d0f5a11480745040a011100181c0c540d13000e44085404404a061716014e010c0308104e084e0d4911450506011853540a5304120a1a154c0a1843001b45541c481607051b431f480d001e0400000c531d01011d00124441010200190d0800000000000e54060001100a1b4d0b040d105347",
		"0a0607000913020d551300041d0f0f0a0003061f154c034f1b53530602004e0c030c541f0454110a1d5a001e0649190419165d00104f104e1b1a101101001b0b1705051b0642040c5341114f0e4b104f0803110b0a060f42",
		"160d074300061d071b524e06190b134e450a0b0a4d4c12411d004f014045491b4649074804001100011d4504520612451e165d53064e16424a1810110c00060d04440e1c02411c0c00544209001953540d165009021a1542",
		"1e10524e001f11481c010010070b13024f0704590903094d0c000e4f0711000615001911454217161a1a45040149000a5218404f1e0012060b1b590a1048171741140c01174c0d49174f4201001f534b0b1c074b",
		"1a49134d4113540a0713490d434e160f541700174f4c11480c53520a1d1100000000190d4549114512544d12000c540402034b4e0d491d40"
	],
	"cipher_flag": "1a4905410f06110c55064f430a00054e540c0a591603174c0d5f000d1b110006414c1848164516111f1100111d1b54001c17474e0e001c011f1d0a4b"
}
	
	

However, on this challenge something is wrong as same key was reused more than once - which I then used to break the encryption. The attack for this is called many time pad attack. To understand how this attack works, below is a short explaination of it.
Note:

⊕ is bitwise xor operator. This symbol means to take the xor individually of each bit pair of the message. For example, we have two messages (C1 and C2), and you have a key (K). For OTP encryption, you would simply do:

C1 ⊕ K = Encrypted

And that will encrypt the original message.
If you then send the Encrypted to someone, and given that they have the key, they would simply do:

Encrypted ⊕ K = C1

And that will give them the original message.
But in case we have:

Encrypted1 = C1 ⊕ K and Encrypted2 = C2 ⊕ K

Now this gets interesting, as we can XOR the two pencrypted text together which will completely remove the key from the equation.

In short:

Encrypted1 ⊕ Encrypred2 = C1 ⊕ K ⊕ C2 ⊕ K = C1 ⊕ C2

All that is left for us is to guess a part of one of the messages, which would in turn give us the corresponding part of the other message.
In summary, in order to attack this encryption and uncover the secret plain text message, we would need to:

  • Guess a word that would probably appear in one of the messages
  • Encode the word into a hex string
  • XOR the two cipher text messages
  • XOR the hex string at each position of the XOR of the two cipher text
  • When the result is readable text, we guess the word and expand our crib search
  • If the result is not readable text, we try a XOR of the crib word at the next position
Solution: We can use the following python script to solve it.

import string
import collections
import sets
import sys
	
# XORs two string
def strxor(a, b):     # xor two strings (trims the longer input)
	return "".join([chr(ord(x) ^ ord(y)) for (x, y) in zip(a, b)])
	
#11 cipher text from cipher_list
c1 = "1b0605000e14000d1b524802190b410700170e10054c11480807001806004e4f1f4f01480d411400531158141e1c100016535a480c000c031a000a160d421e004113010f13451e0c0100100a020a1a4e165f500d0c1e041a090b001d0515521c0a0410000a4f4b4d1d1c184d071600071c0a521d1706540940"
c2 = "1e10524e001f11481c010010070b13024f0704590903094d0c000e4f0711000615001911454217161a1a45040149000a5218404f1e0012060b1b590a1048171741140c01174c0d49174f0c8d4fc7520211531b0b0c1e4f"
c3 = "1d0c04451352001a000154431b014109450a0a0b000045490403520a1d16490008535848085942071c0d0c57101c0045111c40430c4e111c0b1b1c451d4f071712010508475518061d00060a1b0a1a4c165d"
c4 = "160d074300061d071b524e06190b134e450a0b0a4d4c12411d004f014045491b4649074804001100011d4504520612451e165d53064e164e1d060d0d44541a0041031b0b06540d1a070004001d4b074800531c04101d4f"
c5 = "1a1d524912521548120045021b4e1506490a0859150345531d12521b4e094909030003011148420453074d161e05540b071e4c451b000a084a1d1c04084c0b45060b060a4742070618534218070210484512020043100e191e5956111a1c001c1f0b5c"
c6 = "1a1d5248000154041a1c47430d0b04000005015900140c4f04534f094e08490103000000045442111b11001b1b1d000917535a48004e021d4a0e0b0044491c03080a001a024c11490748074f02040054451a1d150c1b150d020d0e"
c7 = "1a1d5249125215481613500a1b0f0d4e4d0d1c0d000700001d1c001b06004f1d0f5a11480745040a011100181c0c540d13000e44085404404a061716014e010c0308104e084e0d4911450506011853540a5304120a1a154c0a1843001b45541c481607051b431f480d001e0400000c531d01011d00124441010200190d0800000000000e54060001100a1b4d0b040d105347"
c8 = "0a0607000913020d551300041d0f0f0a0003061f154c034f1b53530602004e0c030c541f0454110a1d5a001e0649190419165d00104f104e1b1a101101001b0b1705051b0642040c5341114f0e4b104f0803110b0a060f42"
c9 = "160d074300061d071b524e06190b134e450a0b0a4d4c12411d004f014045491b4649074804001100011d4504520612451e165d53064e16424a1810110c00060d04440e1c02411c0c00544209001953540d165009021a1542"
c10 = "1e10524e001f11481c010010070b13024f0704590903094d0c000e4f0711000615001911454217161a1a45040149000a5218404f1e0012060b1b590a1048171741140c01174c0d49174f4201001f534b0b1c074b"
c11 = "1a49134d4113540a0713490d434e160f541700174f4c11480c53520a1d1100000000190d4549114512544d12000c540402034b4e0d491d40"
	
ciphers = [c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11]
	
# The target ciphertext we want to crack
target_cipher = "1a4905410f06110c55064f430a00054e540c0a591603174c0d5f000d1b110006414c1848164516111f1100111d1b54001c17474e0e001c011f1d0a4b"
	
# To store the final key
final_key = [None]*150
# To store the positions we know are broken
known_key_positions = set()

# For each ciphertext
for current_index, ciphertext in enumerate(ciphers):
	
	counter = collections.Counter()
	# for each other ciphertext
	for index, ciphertext2 in enumerate(ciphers):
		if current_index != index: # don't xor a ciphertext with itself
			for indexOfChar, char in enumerate(strxor(ciphertext.decode('hex'), ciphertext2.decode('hex'))): # Xor the two ciphertexts
				# If a character in the xored result is a alphanumeric character, it means there was probably a space character in one of the plaintexts (we don't know which one)
				if char in string.printable and char.isalpha(): counter[indexOfChar] += 1 # Increment the counter at this index
	knownSpaceIndexes = []
	
	# Loop through all positions where a space character was possible in the current_index cipher
	for ind, val in counter.items():
		# If a space was found at least 7 times at this index out of the 9 possible XORS, then the space character was likely from the current_index cipher!
		if val >= 7: knownSpaceIndexes.append(ind)
	#print knownSpaceIndexes # Shows all the positions where we now know the key!

	# Now Xor the current_index with spaces, and at the knownSpaceIndexes positions we get the key back!
	xor_with_spaces = strxor(ciphertext.decode('hex'),' '*150)
	for index in knownSpaceIndexes:
		# Store the key's value at the correct position
		final_key[index] = xor_with_spaces[index].encode('hex')
		# Record that we known the key at this position
		known_key_positions.add(index)
	
# Construct a hex key from the currently known key, adding in '00' hex chars where we do not know (to make a complete hex string)
final_key_hex = ''.join([val if val is not None else '00' for val in final_key])
# Xor the currently known key with the target cipher
output = strxor(target_cipher.decode('hex'),final_key_hex.decode('hex'))
# Print the output, printing a * if that character is not known yet
print ''.join([char if index in known_key_positions else '*' for index, char in enumerate(output)])

'''
Manual step
'''
# From the output this prints, we can manually complete the target plaintext from:
# The secuet-mes*age*is: Wh** usi|g **str*am cipher, nev***use th* k*y *ore than onc*
# to:
# The secret message is: When using a stream cipher, never use the key more than once

# We then confirm this is correct by producing the key from this, and decrpyting all the other messages to ensure they make grammatical sense
target_plaintext = "i wanted to end the"
print target_plaintext
key = strxor(target_cipher.decode('hex'),target_plaintext)
for cipher in ciphers:
	print strxor(cipher.decode('hex'),key)
print "\n===========\nRecovered key: "+key+"\n===========\n"
	
	

The result is

* *anted to ind t** y*rl*, but i'*l*settle for endin* ****s.
i wanted to end the
how often have i sa
my name is sherlock
never trust to gene
education never end
it is a great thing
it has long been an
it is a capital mis
you have a grand gi
education never end
my name is sherlock
i am a brain, watso

===========
Recovered key: sir arthur conan do
===========

	

By using the script and modifying the target plaintext value to match the correct words by guessing intelligently, would result on finding out that the target plaintext is a quote by Sir Arthur Conan Doyle.

I wanted to end the world, but I'll settle for ending yours.

Flag is

radio{i wanted to end the world, but i'll settle for ending yours.}
							
						


Level: Medium



This was the landing page for the CTF medium level



Medium - Challenge 12 - "WEP!"



The first challenge in the medium level is to find the password of a WIFI network protected with WEP encryption.
This can be done easily with Aircrack-ng suit and similar tools, therefore I'm not going to explain this to you. You may refer one of the numerous articles in the web such as this.



Medium - Challenge 13 - "Packets"



Provided with the captured packets, we can check for the flag in pcap dumps.
Opening the packet dump in Wireshark, we can find 31 packets captured

When we start sifting through the packet we can find a username logging in with username as Jerry and password as saymynameheisenberg
There you have it

DSICTS{saymynameheisenberg}


Medium - Challenge 14 - "Steg Horse"



The next challenge consists of two parts. Steganography and cryptography
1st part

You will be given the following image

As the challenge informs us the first part is a steg challenge.

Steganography is the art and science of concealing messages within other messages, documents, or specific file formats, this is the official definition.

The first step is to find any visible or invisible clues in the picture.
Analyzing the codec comes next.

So import the image into any steg-solving tool such as "Stegsolve", "Quick Stego" etc.
Stegsolve is a java based tool that lets you switch between various colour filters quickly.
And so we get the following deciphered image.

Somehow 'd' appears as 'c'. So you will have a hard time. So to prevent it I also added a site called cank.horse in the challenge so competitors won't waste time on guessing that 'c' is actually 'd'

So now you can go to ../dank.horse

You may not go straight to '../dank.horse/flag.pdf' you will instead go to '../dank.horse'
Idk why. But it is tempting to do in a CTF.
So let's go to '../dank.horse'

You will land on a decoy image made to distract you. However you will jump in to Stegsolve and waste about 10 minutes till you decide that this is actually a hose.
Then you will go to the real url '../dank.horse/flag.pdf'

Don't get discouraged. Just download the pdf and start analyzing.

The subject has a link that leads to a .zip file 😀 Let’s look at it…

'../dank.horse/flag.zip'

When you unzip it you will get another 'flag.zip'. However you will notice that this is corrupted

Then the most sensible path is to use a tool to compare the two 'flag.pdf' files and find something out. But you won't find anything (guranteed 😀)
Then we must try strings and find anything hidden in the codec. But again you won't find anything (guranteed again 😀)

So now we only have to analyze the 'flag.zip' file.

Ahoy!. We got something. So let's try to find out the encoding type of this string.
When we analyze is using a service such as "Hash analyzer" we will find out that this is in base64
But if you decode it using that way you will get Unicode characters.
So the deduction is this is the "WRONG WAY".

So let's take a look at the first steg picture for a clue.

In the second line of the deciphered image we have

32(16)

32 means base32 and 16 means base16. We know that base16 is hex.
So we need to decode the base32..

Now we just have to decode the base16(HEX) of it

cdc{empty_pdf_zip_hidden_in_plain_sight}


Medium - Challenge 15 - "Flags everywhere!"



The challenge give us this..
While Sira was looking through his letters he came across a very strange one. Help him decode the the letter in order to fulfill his wish.

and a image.
Following is the last 8 lines in it.

The first look at this will give us an understanding that this is substitution cipher.
So basically you need to find something you know, and then substitute to other lines to deduce the meaning.

You can just bruteforce this by using a tool, but the real fun in solving a sub-cipher can only be obtained by solving it in the old fashioned way.

Guessing..!!

The whole challenge depends on one point.
Identifying the line which we already know.
This step will require some hardcore guessing and patience.
How ever that line is the one above the last line.

As we see there are 3 words.

So we can deduce that this is "The flag is"
So now just substitute it to the last line

Flag: X-MAS{youaresogoodatsubstitutionciphers}


Medium - Challenge 16 - "Amnesic"



We get a file named amnesic.txt which is hard to open with a text editor
This is not a text file.

This is actually an image file. we need to rename it to amnesic.jpg to view it

Binwalk the image to get secret.txt embedded inside the image. With binwalk extract the file embedded in the image, we get a secret.txt with the file.
The flag will be

DSICTS{wowyouaregoodatthis}


Medium - Challenge 17 - "Hexadecimal"



We are given the cyphertext

2e2f3a2631231e1c2a10450d241320452445022a0a2145210c06112c0a0b24171c18

With the Description, you can decide that it is a Single byte XOR which is encrypted using a key

Hence get the key thus receiving the key and the same key is used to decrypt rest of string.
flag is

KJ_CTF{yOu hAvE A gOoD DictIonAry}


Medium - Challenge 18 - "Router!"



This is one of the easiest of the whole competition

We get the login page of the router

We can try in the default values such as

  • user admin
  • admin password
  • admin admin
  • user user

In this case it is

admin admin




Medium - Challenge 19 - "Decipher"



This challenge gives us a enc.txt file

The ciphertext in enc.txt is only provided with jumbled text, neither of the keys was available nor the algorithm is known.
Which makes us conclude it maybe Base64 encoding, Caeser cipher or Rot13 encoding.
The ciphertext is not having alphanumeric characters and the = padding at end of the string is also missing which takes base64 out of guess.
Caesar cipher can be tested with all possible 26 keys but none of the outcomes will be meaningful.

Coming to Rot13, when we decode the ciphertext, we get another set of meaningless ciphertext but when you search for DSICTS{, you can find the flag in the decoded text.

DSICTS{crypto_first_flag}

Medium - Bonus



This is an exciting challenge since it is a kind of clue hunt

This challenge was taken from http://www.pythonchallenge.com/

The first page gives us

So as the hint says lets change URL to 238..

Oops.. On second thoughts it actually is 238. 238 equals to 274877906944. So lets apply 274877906944

I is correct. And the challenge redirects us to another one named "map"

After some time you will notice that the challenge refers to a substitution cypher.

Where K becomes M and O becomes Q and so on..

If you are familiar with this field you will notice right away this is the caesar's shift on the key 2

Or simply put this scheme simply shifts the original by two characters to encrypt the text. So if we encrypt "abcd" we will get "cdef".
So if we input

g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp.
bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle.
sqgle wmsp mul ambc gq pcamkkclbcb. lmu ynnjw ml rfc spj.

we will get..

ihopeyoudidnttranslateitbyhandthatswhatcomputersarefordoingitinbyhandisinefficientandthatswhythistextissolongusingyourowncodeisrecommendednowapplyontheurl

Just don't do this by hand. Automate it. It is a simple code
However let's apply it on the URL

So "map" becomes "ocr"

So let's view the page source

There is a mess of characters. But if we look closely, most of them are special characters such as !@#$ etc.
We just have to filter out the alphabetical characters. Just as before automate the process

Then we get the answer "equality"

No visible clues. So onto the page source..

This is a bit complex than the previous one. We have to find simple characters which are surrounded by THREE CAPITAL letters on each side. Now I don't need to say to automate it.

We will get "linkedlist"

Once again no visible clues. So...

We can see a link linkedlist.php?nothing=12345 So let's pay a visit

So let's feed it to the GET parameter "nothing". Then we get

If you are interested the PHP code I created for this challenge is as follows

<?php
    session_start();
    if(isset($_GET['nothing'])){
        $nothing = $_GET['nothing'];
        if($nothing == "654654")
            die("peak.php");
            
        if(!isset($_SESSION['nothings']))
            $_SESSION['nothings'] = 0;
        
        if($_SESSION['nothings']>=400)
            die("and the next nothing is 654654");

        if(isset($_SESSION['current'])){
            $num = rand(10000, 99999);
            if($nothing == $_SESSION['current'])
                $_SESSION['nothings']++;
            echo "and the next nothing is $num";
            $_SESSION['current'] = $num;
        }else if($nothing == "12345"){
                $num = rand(10000, 99999);
                $_SESSION['current'] = $num;
                echo "and the next nothing is $num";
            }
        }

        // echo "<br/>" . $_SESSION['nothings'] . "<br/>" . $_SESSION['current'];
        die;
    }
?>
<html>

<head>
    <title>Follow the chain</title>
    <style>
        * {
            font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
            background-color: rgb(51, 51, 51)
        }
    </style>
</head>

<body>
<!-- Try urllib in python. DON'T TRY ALL NOTHINGS, since it will never 
end. 444 times is more than enough. -->
    <center>
    <a href="linkedlist.php?nothing=12345"><img src="./imgs/chainsaw.jpg"/></a>
    </center>
</body>

</html>
						

So the point is you must enter the previous (only the previous not the previous of the previous; Yaa it's a bit confusing) to the current page and so on for 400 times

This challenge was specifically created to block out those contestents who didn't automate the processes and those who tried to bruteforce their way out

Now we got peak.php

The challenge title is peak hell. If we pronounce it repeatedly it sound like
peak hell.. peakhell... peakell ... pickle. Aha pickle

Ooops; dead end. Looks like we are in a bit of a 'pickle' here aren't we??

In the page source of the peak hell page we can find a perl file

Lets open the benner.p

If you look again we know it. "pickle" is the Python's object serialization module. So let's deserialize it using pickle

import pickle
data = pickle.load(urlopen("http://127.0.0.1/Hacking_Challenge/Medium/bonus/banner.p"))
print(data)
						

The output is

[[(' ', 95)], [(' ', 14), ('#', 5), (' ', 70), ('#', 5), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 15), ('#', 4), (' ', 71), ('#', 4), (' ', 1)], [(' ', 6), ('#', 3), (' ', 6), ('#', 4), (' ', 3), ('#', 3), (' ', 9), ('#', 3), (' ', 7), ('#', 5), (' ', 3), ('#', 3), (' ', 4), ('#', 5), (' ', 3), ('#', 3), (' ', 10), ('#', 3), (' ', 7), ('#', 4), (' ', 1)], [(' ', 3), ('#', 3), (' ', 3), ('#', 2), (' ', 4), ('#', 4), (' ', 1), ('#', 7), (' ', 5), ('#', 2), (' ', 2), ('#', 3), (' ', 6), ('#', 4), (' ', 1), ('#', 7), (' ', 3), ('#', 4), (' ', 1), ('#', 7), (' ', 5), ('#', 3), (' ', 2), ('#', 3), (' ', 5), ('#', 4), (' ', 1)], [(' ', 2), ('#', 3), (' ', 5), ('#', 3), (' ', 2), ('#', 5), (' ', 4), ('#', 4), (' ', 3), ('#', 3), (' ', 3), ('#', 4), (' ', 4), ('#', 5), (' ', 4), ('#', 4), (' ', 2), ('#', 5), (' ', 4), ('#', 4), (' ', 3), ('#', 3), (' ', 5), ('#', 3), (' ', 3), ('#', 4), (' ', 1)], [(' ', 1), ('#', 3), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 3), (' ', 4), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 6), ('#', 4), (' ', 2), ('#', 4), (' ', 1)], [(' ', 1), ('#', 3), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 10), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 7), ('#', 3), (' ', 2), ('#', 4), (' ', 1)], [('#', 4), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 5), ('#', 2), (' ', 3), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 7), ('#', 3), (' ', 2), ('#', 4), (' ', 1)], [('#', 4), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 10), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#', 14), (' ', 2), ('#', 4), (' ', 1)], [('#', 4), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 4), ('#', 4), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 12), ('#', 4), (' ', 1)], [('#', 4), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 5), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 12), ('#', 4), (' ', 1)], [(' ', 1), ('#', 3), (' ', 11), ('#', 4), (' ', 5), ('#', 4), (' ', 1), ('#', 4), (' ', 5), ('#', 3), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 12), ('#', 4), (' ', 1)], [(' ', 2), ('#', 3), (' ', 6), ('#', 2), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 3), (' ', 4), ('#', 4), (' ', 4), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 3), (' ', 6), ('#', 2), (' ', 3), ('#', 4), (' ', 1)], [(' ', 3), ('#', 3), (' ', 4), ('#', 2), (' ', 3), ('#', 4), (' ', 5), ('#', 4), (' ', 3), ('#', 11), (' ', 3), ('#', 4), (' ', 5), ('#', 4), (' ', 2), ('#', 4), (' ', 5), ('#', 4), (' ', 4), ('#', 3), (' ', 4), ('#', 2), (' ', 4), ('#', 4), (' ', 1)], [(' ', 6), ('#', 3), (' ', 5), ('#', 6), (' ', 4), ('#', 5), (' ', 4), ('#', 2), (' ', 4), ('#', 4), (' ', 1), ('#', 6), (' ', 4), ('#', 11), (' ', 4), ('#', 5), (' ', 6), ('#', 3), (' ', 6), ('#', 6)], [(' ', 95)]]
						

OK! So data is a list of lists of tuples... It does not look like a banner(the file name), but more like the result of a simple string compression: convert the repetitive characters to tuples of (character, number of appearance). This level is all about serialization and compression, isn't it. Let's unravel the string:

If you are not in a hurry you can decypher this by hand. (Just the first few, for FUN)
If we get the first list it says ' ' character for 95 times
Then ' ' character for 14 times
Then '#' character for 5 times. an so on...
But let's devise a code..

for line in data:
	print("".join([k * v for k, v in line]))
						

The output will be

																								   
              #####                                                                      ##### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
               ####                                                                       #### 
      ###      ####   ###         ###       #####   ###    #####   ###          ###       #### 
   ###   ##    #### #######     ##  ###      #### #######   #### #######     ###  ###     #### 
  ###     ###  #####    ####   ###   ####    #####    ####  #####    ####   ###     ###   #### 
 ###           ####     ####   ###    ###    ####     ####  ####     ####  ###      ####  #### 
 ###           ####     ####          ###    ####     ####  ####     ####  ###       ###  #### 
####           ####     ####     ##   ###    ####     ####  ####     #### ####       ###  #### 
####           ####     ####   ##########    ####     ####  ####     #### ##############  #### 
####           ####     ####  ###    ####    ####     ####  ####     #### ####            #### 
####           ####     #### ####     ###    ####     ####  ####     #### ####            #### 
 ###           ####     #### ####     ###    ####     ####  ####     ####  ###            #### 
  ###      ##  ####     ####  ###    ####    ####     ####  ####     ####   ###      ##   #### 
   ###    ##   ####     ####   ###########   ####     ####  ####     ####    ###    ##    #### 
      ###     ######    #####    ##    #### ######    ###########    #####      ###      ######
			

We got it!! channel. So onto next one

Nothing interesting going on here. Let's view the source

See that <!-- <-- zip --> it must be a clue. So let's apply it to the url. add ".zip" to end

A zip file is downloaded. Let's open it

A readme file is inside. It says to start from 90052. So let's do exactly that

import zipfile, re

f = zipfile.ZipFile("resources/channel.zip")
num = '90052'
while True:
	content = f.read(num + ".txt").decode("utf-8")
	print(content)
	match = re.search("Next nothing is (\d+)", content)
	if match == None:
		break
	num = match.group(1)						
						

output is

Next nothing is 94191
Next nothing is 85503
Next nothing is 70877
...
Next nothing is 68628
Next nothing is 67824
Next nothing is 46145
Collect the comments.		
						

Comments.. what comments?

It turns out that zip file can contain some comments, and they can be accessed by:
ZipFile.comment: comment associated with the ZIP file.
ZipInfo.comment: comment for the individual archive member.
Add a few lines to collect the comments:

num = '90052'
comments = []
while True:
	content = f.read(num + ".txt").decode("utf-8")
	comments.append(f.getinfo(num + ".txt").comment.decode("utf-8"))
	content
	match = re.search("Next nothing is (\d+)", content)
	if match == None:
		break
	num = match.group(1)

print("".join(comments))	
								

outout will be

****************************************************************
****************************************************************
**                                                            **
**   OO    OO    XX      YYYY    GG    GG  EEEEEE NN      NN  **
**   OO    OO  XXXXXX   YYYYYY   GG   GG   EEEEEE  NN    NN   **
**   OO    OO XXX  XXX YYY   YY  GG GG     EE       NN  NN    **
**   OOOOOOOO XX    XX YY        GGG       EEEEE     NNNN     **
**   OOOOOOOO XX    XX YY        GGG       EEEEE      NN      **
**   OO    OO XXX  XXX YYY   YY  GG GG     EE         NN      **
**   OO    OO  XXXXXX   YYYYYY   GG   GG   EEEEEE     NN      **
**   OO    OO    XX      YYYY    GG    GG  EEEEEE     NN      **
**                                                            **
****************************************************************
 **************************************************************
								

We got an answer "hockey"

Apparently not. Just a little fun
The right answer is in the letters: oxygen