Juego: Cybercamp 2015 – Fase 2
Actually, this challenge was not really a Web challenge, as the goal was mainly to read a image, but it was really a fun challenge 🙂
So, the main page looked like this :
As you can see, there is only a blank image (loaded with php, in imagen.php file)and a form asking us for a code, which should certainly be in the image. So, we have to analyze it. After a bit of guessing, we found out that the image is not actually really blank. There is a single byte difference in some pixels. After filling some parts, we rapidly saw that the image was actually a QR code :
We tried to read it, but as we filled it by hand, some pixels were bad and nothing came. We then created a little script that filled the image as it should:
from PIL import Image pic = Image.open('tmpfile.png') pic = pic.convert('RGBA') pix = pic.load() (width, height) = pic.size for i in range(pic.size): for j in range(pic.size): #print(pix[i,j]) if (pix[i,j]!= (255, 255, 255, 255)): pix[i,j] = (0, 0, 0, 255) pic.save('imagen3_parsed.png')
The QR code gived us its value : CAX LXVKXM VHWX BL: TRRYLKROSTYJLXVVMONOLNLWKYWXQKMS.
After a few tests, we discovered that it was a caesar cipher with a random key. The decoded valus was ‘The secret code is: ‘ with a code behind. We tried this code in the web page form, but we had an error message saying that the code was false. OK, so, it’s a bit like a catcha, everytime the image page is loaded, a new code is generated.
Oh and moreover, the main page says that we succeeded “0 time” so, obvisouly, we had to succeed multiple times. The best to do was then to create a little script.
To sum up, we have to :
- get a session that we have to keep
- get the nearly white image
- add some black onto the image, in order to read the QR Code
- read the QR Code
- “Brute force” the caesar to get the good key
- Send it to the webpage
- Do it again and again (except the session of course, which must be the same)
So this is our code (python2) :
# -*- coding: utf-8 -*- from PIL import Image import qrtools import socket import request import sys def caesar(s, key): ret = "" for i in s: al = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' if (i ==' '): ret += ' ' elif(i == ':'): ret +=':' else: ret += al[(al.find(i)+1+key)%62] return ret req = request.request() req.dst = "challenge.cybercamp.es" req.host = "challenge.cybercamp.es" req.method = "GET" req.port = 8091 req.uri = "/" req.version = "HTTP/1.1" # first we get the session cookie rep = req.send() if rep.cookies: req.cookies = rep.cookies[0:rep.cookies.find(";")] # then we get the f*cking imagen.php file a thousand time aa=0 while (aa< 1000): req.uri = "/imagen.php" rep = req.send() tmpf = open('tmpfile.png', 'wb') tmpf.write(rep.body) tmpf.close() #print(rep.response.encode('UTF-8')) pic = Image.open('tmpfile.png') pic = pic.convert('RGBA') pix = pic.load() (width, height) = pic.size for i in range(pic.size): for j in range(pic.size): if (pix[i,j]!= (255, 255, 255, 255)): pix[i,j] = (0, 0, 0, 255) pic.save('imagen3_parsed.png') qr = qrtools.QR() qr.decode('imagen3_parsed.png') print(qr.data) i = 0 msg = "" while not 'secret' in msg: msg = caesar(qr.data, i) i+=1 req.uri = "/?respuesta="+msg.split(': ') rep = req.send() print rep.response aa+=1
Finally, we launched the script, kept an eye on our console to see the responses coming and… the flag !
<html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> <meta name="description" content=""> <meta name="author" content=""> <link rel="icon" href="favicon.ico"> <title>Web - Challange 11</title> <!-- Bootstrap core CSS --> <link href="css/bootstrap.min.css" rel="stylesheet"> <!-- Custom styles for this template --> <link href="css/jumbotron-narrow.css" rel="stylesheet"> <!-- Just for debugging purposes. Don't actually copy these 2 lines! --> <!--[if lt IE 9]><script src="../../assets/js/ie8-responsive-file-warning.js"></script><![endif]--> <script src="js/ie-emulation-modes-warning.js"></script> <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> </head> <body> <div class="container"> <div class="header clearfix"> <nav> </nav> <h3 class="text-muted">Challange 11: White</h3> </div> <div class="jumbotron"> <h1>Do you see it?</h1> <center> TOKEN: fe84d2417a135e8fe3b4e6b0fb947334 </center> </center> </div> <footer class="footer"> <p>© Web Challange 11 - 2015</p> </footer> </div> <!-- /container --> <!-- IE10 viewport hack for Surface/desktop Windows 8 bug --> <script src="js/ie10-viewport-bug-workaround.js"></script> </body> </html>
Here is the flag : fe84d2417a135e8fe3b4e6b0fb947334