Harekaze CTF 2018 - Write-ups

Information#

Version#

By Version Comment
noraj 1.0 Creation

CTF#

  • Name : Harekaze CTF 2018
  • Website : harekaze.com
  • Type : Online
  • Format : Jeopardy
  • CTF Time : link

30 - easy problem - WarmUp#

Do you know ROT13? Can you decode this text? UnerxnmrPGS{Uryyb, jbeyq!}

Here is my Ruby script for Caesar cipher, here we already know it is ROT13

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env ruby

# from https://gist.github.com/matugm/db363c7131e6af27716c
def caesar_cipher(string, shift = 1)
alphabet = Array('a'..'z')
encrypter = Hash[alphabet.zip(alphabet.rotate(shift))]
# " " => c because I don't want to void non-letters chars
string.chars.map { |c| encrypter.fetch(c, c) }
end

text = 'UnerxnmrPGS{Uryyb, jbeyq!}'
text.downcase! # put lowercase

(1..25).each do |i|
puts "#{i}: " + caesar_cipher(text, i).join + "\n\n"
end

The flag is harekazectf{hello, world!}.

40 - recursive zip - WarmUp#

Do you know unzip?

flag.zip

I made a dirty script in ruby to recursively unzip the archive:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require 'archive/zip'
require 'fileutils'

filename = 'flag.zip'
basename = filename.chomp('.zip')
extract_folder = basename + '/'

while true
FileUtils::mkdir_p extract_folder
Archive::Zip.open(filename) do |z|
z.extract(extract_folder, flatten: true)
end
Dir.chdir extract_folder
# dirty, wait for 'No such file or directory @ rb_sysopen - flag.zip (Errno::ENOENT)'
end

As the script preserves the file tree, make a recursive ls to find the last directory : ls -R.

Then display the flag.txt: HarekazeCTF{(\lambda f. (\lambda x. f (x x)) (\lambda x . f (x x))) zip}.

100 - Sokosoko Secure Uploader - Web#

I encrypted my file by using this service. Attachment is the encrypted file, but I accidentally deleted the UUID of the file. All I remember is the UUID starts with 9e5a :(

The website looks like this:

Let's read the source code.

In decrypt.php, we can see the SQL query is injactable:

1
2
3
4
5
6
7
$pdo = new PDO('sqlite:key.db');
$stmt = $pdo->query("SELECT key FROM decryption_key WHERE id = '$uuid'");
$res = $stmt->fetch();

if ($res === false) {
die('key not found');
}

So our entry point is the UUID provided by the user. But the UUID must match two conditions:

1
2
3
4
$uuid = $_POST['uuid'];
if (!is_string($uuid) || !is_uuid($uuid)) {
die('invalid UUID');
}

Firstly, UUID needs to be a string, easy for us. Secondly, UUID needs that is_uuid() returns true.

I took a look in functions.php to find is_uuid():

1
2
3
4
5
6
7
8
9
function is_uuid($str) {
if (strlen($str) !== 36) {
return false;
}
if ($str[8] !== '-' or $str[13] !== '-' or $str[18] !== '-' or $str[23] !== '-') {
return false;
}
return true;
}

So the UUID must be 36 char long and needs to have the - char at some specific places. Here, the exploitation will be more challenging as our payload will need to look something like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.

Then I used sqlitebrowser to create a test SQLite database and try some payloads.

We need to respect the xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format and to make a valid SQL payload for this query SELECT key FROM decryption_key WHERE id = '$uuid'.

I found that operators like OR can be stuck to a quote like this 'OR and that C-style inline comments can't split a keyword so SEL/* bla */ECT is not valid but SELECT/* bla */key FROM is.

So I managed to generate the final payload 'OR id/*-*//*-*//*-*//*-*/LIKE '9e5%. Submitting this as the UUID and the encrypted image gave me back the decrypted image containing the flag HarekazeCTF{k41k4n_j1kk4n_j1n615uk4n}.

Share