Timisoara CTF 2018 Quals - Write-ups

Information#

Version#

By Version Comment
Florent 1.0 Creation

CTF#

Invitation - Forensics#

We analyze the PDF file using peepdf in interactive mode :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
florent@kali:~# peepdf -i /root/Desktop/timisoara/invitation/invitation.pdf 

File: invitation.pdf
MD5: 553a0dd891f6170b21275f66232e7472
SHA1: 66eeeac160c0bd861392ef4855490314c5bc0522
Size: 31962 bytes
Version: 1.4
Binary: True
Linearized: False
Encrypted: False
Updates: 0
Objects: 19
Streams: 5
Comments: 0
Errors: 0

Version 0:
Catalog: 1
Info: 4
Objects (19): [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Streams (5): [13, 15, 8, 16, 17]
Encoded (5): [13, 15, 8, 16, 17]
Objects with JS code (1): [3]
Suspicious elements:
/OpenAction: [1]
/JS: [3]
/JavaScript: [3]

As we can see, there is a JS object inside the file.

We retrieve it :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
PPDF> object 3

<< /Type /Action
/S /JavaScript
/JS // https://www.gnostice.com/nl_article.asp?id=310&t=An_Acrobat_Javascript_primer_with_simple_PDF_examples
// I'll adapt this to our document, now we validate using email so I have enough time to learn PDF Javascript'ing
static void create_PDFWithFormValidation() {
PDFDocument doc = new PDFDocument(PDFOne_License.KEY);
doc.OpenAfterCreate = true;
doc.MeasurementUnit = PDFMeasurementUnit.Inches;

// Create a text form field
PDFFormTextField tf = new PDFFormTextField(new RectangleF(1f, 1f, 1f, 0.3f));
tf.FieldName = "FullName";
tf.BackgroundColor = Color.LightGray;
tf.NameAsUnicode = false;

// Create a push button form field
PDFFormPushButton pb = new PDFFormPushButton(new RectangleF(1f, 2f, 1f, 0.3f));
pb.FieldName = "SubmitButton";
pb.ActionType = PDFFormFieldActionType.Javascript_Action;
pb.NormalCaption = "Submit";
pb.JavaScript =
"var oNameField = this.getField('FullName'); " +
"if (oNameField.valueAsString.length > 2) { " +
" var arFields = new Array('FullName'); " +
" this.submitForm({ " +
" cURL: 'http://www.gnostice.com/newsletters/demos/200804/forms_test.asp', " +
" aFields: arFields, " +
" cSubmitAs: 'HTML', " +
" }); " +
" // if validation is ok..." +
" // then this at the end, somehow... don't click or access, wait until I learn JS and how it works in PDF!!!!!!!!!" +
" var dlink = 'https://gist.github.com/0xcpu/de7c4c11b59c947bc247ae6d71c9348f';" +
"} else { " +
" app.alert('Nhyet! Nhyet! Nhyet!');" +
"}";

// Add form fields to the document
doc.AddFormField(tf);
doc.AddFormField(pb);

doc.Save("form.pdf");
doc.Close();
}
>>

We can see a hard-coded gist URL. When we go to the URL, we can see a long base64 encoded code block which seems to have been reversed since the padding appears to be at the beginning:

1
2
3
4
5
6
7
8
==Q2//nfcH0mu0daA0VOpq+Ka+ZRvxxCwFPg
kgJyCGok9QGVGuGWaiQ9j/i8LisnZYK7ZGmVqANcaVqccqYP1kCf9qsPeBnRKsRhU2zMM5v+ixTP
/mqMKxAtgtwpiDErgmUrklwpA8vD76ekBpQl3EF1EAQVjK/DO4zq+9K6Xgb1N/1ZsHoQA8v3DvnA
Y15kj8BnCSxd/1wSqsY34w+cqUssWiEmieASVyBQ62KvaRrPLfT5D6Ua0kjN7HX4O2J+1PrADo8x
[...]
AERADMQACDACRAgw/HQABEQABEQABEQABEQABEQABEQABEQABEQABEQABEQABEQABEQABEQABEQA
BEQABEQABEQABEQABEQABEQABEQADBw2/HQABEQABEQABEQABEQABEQABEQABEQABEQABEQABEQA
BEQABEQABEQABEQABEQABEQABEQABEQABEQABEQABEAADBw2/DAAIBASAEQABAgRJZkSQAA4/j9/

We save the snippet to a file and we use the following Python code to decode it:

1
2
3
4
5
6
#!/usr/bin/python

from base64 import b64decode

d = open('pandagif2.txt', 'rb').read().replace('\n', '')[::-1]
e = open('kek', 'wb').write(b64decode(d))

The output is an image on which the flag can be read.

Picassor - Crypto#

The challenge is a file called unirii_square.jpg.

However, we cannot open the file as it is and the file command returns the following output :

1
2
florent@kali:~# file unirii_square.jpg 
unirii_square.jpg: data

Since the file has a .jpg extension, we can assume that it is a JPEG file.

We can also assume that the file can easily be decrypted since we have absolutely no clue from the challenge description about what we have to do.

At this point, what first comes to mind is that it might be XORed.

We know that the header signature of JPEG starts with 0xFF 0xD8 0xFF 0xE0 so we can XOR the first four bytes of the ciphered file with the four bytes of the header signature in order to retrieve the key or a part of the key.

After some manual analysis, it appears that the key is the single byte 0xAB.

We use the following Python script to decrypt the file :

1
2
3
4
5
6
7
8
9
#!/usr/bin/python

f = open('unirii_square.jpg', 'rb').read().strip()

key = ord(f[0]) ^ 0xFF

g = open('output.jpg', 'wb')
for char in f:
g.write(chr(key ^ ord(char)))

We get an image on which the flag is printed.

Share