DART CTF - Objective 3
DART CTF - Objective 3 Walkthrough
Objective 3
Task
- Extract information about Azure Functions in the target environment.
- Use a function key to retrieve Flag 3 from a function.
- Find Flag 4 by using a logic app parameter.
- Use a function key from the above task to retrieve Flag 5 from another function.
- Use a function key from the above task to retrieve Flag 6 from another function.
Solution
Lets continue analysing and understanding the code we identified in Objective - 2. The code appears to implement a simple encryption mechanism using the XOR bitwise operation. Let’s break down the script:
1
2
3
4
5
6
7
8
9
10
11
Imp = b'Use the same carefully'
MyValue = b'a*)h\x1f/!U9&\x1f\x1cz\x19\x038\r%/?\x15)\x10\x1d\t\x15A\\\nt&S8:L2%7\tW\x1dZ54\x14\t#U8\r?b70PX'
def enc(MyValue):
bytevalue = bytearray()
for i in range(len(MyValue)):
bytevalue.append(MyValue[i] ^ Imp[i % len(Imp)])
return bytes(bytevalue)
value = enc(MyValue.encode())
print(value)
- Variables:
Impis a byte string. In Python,b''denotes a byte string.MyValueis another byte string.
- Function
enc:- This function takes a byte string as input and creates an empty
bytearray, which is a mutable sequence of bytes. - The function then iterates over each byte in the input byte string.
- For each byte, it performs an XOR (
^) operation with the corresponding byte inImp. The use ofi % len(Imp)ensures that ifMyValueis longer thanImp, the process will loop back to the start ofImp. - The result of each XOR operation is appended to the bytearray.
- Finally, the
bytearrayis converted back to a bytes object and returned.
- This function takes a byte string as input and creates an empty
- Encryption Process:
- The script calls
encwithMyValue.encode(). The XOR operation is a common method for simple encryption. When you XOR a piece of data with a key, you can reverse the process by XORing the result with the same key.
- The script calls
- Print Statement:
- The script prints the result of the
encfunction, which should be the obfuscated version ofMyValue.
- The script prints the result of the
However, since MyValue is already a byte string, .encode() is not needed and will cause an error.
Instead we can pass MyValue directly to the enc function.
1
2
3
4
5
6
7
8
9
10
11
12
Imp = b'Use the same carefully'
MyValue = b'a*)h\x1f/!U9&\x1f\x1cz\x19\x038\r%/?\x15)\x10\x1d\t\x15A\\\nt&S8:L2%7\tW\x1dZ54\x14\t#U8\r?b70PX'
def enc(MyValue):
bytevalue = bytearray()
for i in range(len(MyValue)):
bytevalue.append(MyValue[i] ^ Imp[i % len(Imp)])
return bytes(bytevalue)
value = enc(MyValue)
print(value)
Smooth. Now we have a Key. Earlier on when we fuzzed the test parameter we found two possible parameter’s that we can visit, i.e action & debug. So far we’ve explored debug . TIme to check out action. On visiting the following URL:
1
https://prod-61.eastus.logic.azure.com/workflows/250827f3ebc54c368f85643619f38ce3/triggers/manual/paths/invoke/action?api-version=2018-07-01-preview&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=avLLG0xOCALGGT-7zmIJsddcUiL5o2GOijT4mPSA4JY
we get another python script and Flag 4
Lets dissect it:
The function
retrieveis defined to accept acodeparameter.If a code is provided , the function uses the requests library to send an HTTP GET request to https://rosarray.azurewebsites.net/api/Canister and appends the provided code as a query parameter.
After making the request, the function checks the HTTP status code of the response.
Outside of the
retrievefunction, the code variable is set to a specific string. Theretrievefunction is then called with this code, and the result is stored in the variable results.The code checks if the results contain an “error” key:
Basically this code interacts with an API endpoint that requires a security code for access. The code variable likely represents an API key or token that grants access to the Canister function in the Azure Functions app hosted at rosarray.azurewebsites.net.
With this in mind, lets try access the endpoint using the previously decrypted code:
1
http://rosarray.azurewebsites.net/api/Canister?code=4YLHkGDuJGryZzbJhCZSyPEnl554oTU2U_lQDEl1h6YMAzFuLeZBDQ==
But hold that thought there. While exploring the blob earlier using Azure Windows Storage Explorer, i recall seeing a directory called rosarray in the blob container azure-webjobs-secrets. Lets go back and check if we can find more functions other than canister.
This time we find blanket and deployer.
host.json looks interesting, let’s view it.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"masterKey": {
"name": "master",
"value": "CfDJ8AAAAAAAAAAAAAAAAAAAAAAzpeADcTSwJp_43EQyqIRSd-uDekfdk8Wsk-wIMBlo3GD8da3dL59uaDtstCis3_UB1j-mA_U6zkjKg2cCZxHC7AOPogXiTLiLeUIhO7AJxh5LslOn51LNWNetdEYjPxiWAT4Vl5mVJoJ_DmvZ_PRinq7Sv3jWs1Q7gVO7C_VxtQ",
"encrypted": true
},
"functionKeys": [
{
"name": "default",
"value": "CfDJ8AAAAAAAAAAAAAAAAAAAAABzWmb45YZ95DyetB5fIg--SuQR1bxk4UZ2s8lYXmY3ODMFoPj4wPJWqUupY3OYCvqwGAXQAjVbHDjoBmn7QMDlquz8BNpjEOtZY70apNKmNk1228gnA5FK4F306Ra6awG_cooIuKAuVPTC6RUiHRBkHctVagML4o03bvzsrIhG0w",
"encrypted": true
}
],
"systemKeys": [],
"hostName": "rosarray.azurewebsites.net",
"instanceId": "0000000000000000000000002B233D22",
"source": "runtime",
"decryptionKeyId": "AzureWebEncryptionKey=71K9CPtGDRphMirq9D21FkBghc3YmeQlIbrYA93zK1c=;"
}
The JSON content appears to be a configuration file for an Azure Function application. It contains various keys used by the Azure Functions host. Here’s a breakdown of the contents:
- masterKey:
- name: A label for the key, here it is “master”.
- value: The actual key value, which appears to be encrypted. This key is typically used to provide administrative access to the function app.
- encrypted: Indicates that the key is stored in an encrypted form.
- functionKeys:
- A list of keys that are used to provide access to individual functions within the app.
- systemKeys:
- These are keys used by the system, likely for internal Azure processes or extensions. In this case, it appears to be an empty array, indicating no system keys are set.
- hostName:
- The DNS name for the function app, which is typically rosarray.azurewebsites.net.
- instanceId:
- A unique identifier for the instance of the function app.
- source:
- Indicates where these keys are coming from; in this case, it’s “runtime”, which suggests that the keys are used at runtime by the Azure Functions host.
- decryptionKeyId:
- This is likely the identifier for the key that is used to decrypt the masterKey and functionKeys.
With that said, lets explore the other three json files:
deployer.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"keys": [
{
"name": "default",
"value": "CfDJ8AAAAAAAAAAAAAAAAAAAAACySloWXZj5BQqDaJAciFzbvl05A5_XcJEysETsnWFCWkssLhWrbMrAkODRp0us2hJz9zZ4Ncpl5f_GcexVKZol7B0ttqzLcv4SEOHYCn8teBEoOLGm5ADlbFI6SBFCytDKgWo3Ko8EhXFbw7ypysRPXrfCMamaKnPYu1twW6Gh0g",
"encrypted": true
}
],
"hostName": "rosarray.azurewebsites.net",
"instanceId": "0000000000000000000000000403D027",
"source": "runtime",
"decryptionKeyId": "AzureWebEncryptionKey=71K9CPtGDRphMirq9D21FkBghc3YmeQlIbrYA93zK1c=;"
}
canister.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"keys": [
{
"name": "default",
"value": "CfDJ8AAAAAAAAAAAAAAAAAAAAAAtCjMDQrEZW7OyShi4qC7autHbJ61Te6GcgFDj7N47Vz0pl04lIqDRtlWz8Tj9038K9CwQs0OsSFO_4E_F8fkGo-D8p81Zlk4h4WLhjyyzwQ1GhW00D4kcib5kGLT02StUHLVKOQI3D7YImDXD6dMZu4MId2zcOlqIe7r7Vda6xw",
"encrypted": true
}
],
"hostName": "rosarray.azurewebsites.net",
"instanceId": "0000000000000000000000006B282786",
"source": "runtime",
"decryptionKeyId": "AzureWebEncryptionKey=71K9CPtGDRphMirq9D21FkBghc3YmeQlIbrYA93zK1c=;"
}
blanket.json
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"keys": [
{
"name": "default",
"value": "CfDJ8AAAAAAAAAAAAAAAAAAAAAD9wsuBOAoIYUE14L8q6MaGzJyQFotW7XZSn1Cf4xTtXF6Pm8RDXB7vRJrmmL0krT0D8O7bZs5dQGED51rUcadQLvGaYYH4aPJzx9lfXarajHe6ZCjChYEU3jtcy265ueSa1k-J6hz2XmP6kjI-gB0yxt3zCf0rkhJOjgR6-6DI3w",
"encrypted": true
}
],
"hostName": "rosarray.azurewebsites.net",
"instanceId": "0000000000000000000000002B233D22",
"source": "runtime",
"decryptionKeyId": "AzureWebEncryptionKey=71K9CPtGDRphMirq9D21FkBghc3YmeQlIbrYA93zK1c=;"
}
deployer.json, canister.json, blanket.json: Likely represent different components or services within the application environment, each with its own set of keys for access and operation.
They all share the same decryptionKeyId, which implies they use the same encryption key for encrypting and decrypting the stored keys.
Lets now continue testing if we get any results with blanket and deployer functions:
1
2
http://rosarray.azurewebsites.net/api/Blanket?code=4YLHkGDuJGryZzbJhCZSyPEnl554oTU2U_lQDEl1h6YMAzFuLeZBDQ==
http://rosarray.azurewebsites.net/api/Deployer?code=4YLHkGDuJGryZzbJhCZSyPEnl554oTU2U_lQDEl1h6YMAzFuLeZBDQ==
I did not succeed with deployer but i got a flag on blanket
Moving on, let’s use the code we found in the python script to access the canister function:
1
http://rosarray.azurewebsites.net/api/canister?code=7CIzVAz1-SRtgbuwRG-PMTnL_BYbDhGaXrU-S-ZTEpDGAzFuCDmwrA==
We get some statistics in a JSON format. We also find a key potentially usable with the deployer function as highlighted. Towards the end of the json you also get Flag 5 🚩
Let’s try access deployer using the key identified:
1
https://rosarray.azurewebsites.net/api/deployer?code=li1u2C-xrQ_xvUA5d18DUKcniUSAAd4NY_tS3KmsnTYGAzFuoYq5vw==
We get a response and the final flag for this objective. (Flag 6)🚩
In Objective - 4 we are going to dive even more deeper into the intricacies of Azure and its componets.
