Each IIS server may be include many websites, each website has Site ID, Physical webroot path, bindings and Root application (and more another applications under child directory):
For example, website1 have: Site ID = 2, Physical Path = C:\website1, Bindings = http:*:81:, two applications (Root application at C:\website1 and app1 application at C:\website1\app1)
Each IIS website can have many applications (at least Root application). Each application will have AppPool Name, Virtual Path and Physical Path.
Each Application will run under only one AppPool.
Each AppPool will have:
- AppPool Name
- LocalSystem, NetworkService, LocalService
- ApplicationPoolIdentity (IIS apppool\<apppool_name> - virtual account)
- Apppool run as C:\windows\system32\inetsrv\w3wp.exe under identity privilege
Now, we have basic aspx file handling as following:
- Step1. User access http://domain:81/index.aspx
- Step2. Binding http:*.81 -> website1 will handle this
- Step3. Virtual path /index.aspx -> Root Application will handle this
- Step4. Root Application runs under website1 apppool -> Launch website1 apppool process (w3wp.exe) under "IIS apppool/website1" identity
- Step5. Apppool process (w3wp.exe):
- From virtual path /index.aspx, get physical path C:\website1\index.aspx and read aspx content
- Translate to C# sourcecode
- Launch csc.exe to build C# sourcode into dll
- Load dll, init a Page instance and call Page.OnLoad()
Aspx file build process only runs when the file is accessed for the first time or when the file is changed.
So dll compiled file must be cached at somewhere. The cache algorithm is simple as below:
And this is the folder to save the cache data:
The cache data for virtual path /index.aspx is saved in file index.aspx.cdcab7d2.compiled in folder C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\root\4c305858\252b41dd\
You will see the assembly and type property. The virtual path /index.aspx will be handled by App_Web_ssm44hrj.dll and type ASP.index_aspx of that assembly.
And now is more information for this data:
How I know this information. That's quite simple. I attached w3wp.exe in dnSpy and reverse + debug it. Most related code is in System.Web.Compilation namespace of System.Web.dll
"code gen dir"
Here is the algorithm to calculate "code gen dir" of an application (you need to know the physical path and appid)
For example, website1 (Site ID=2) have two applications:
- Root application (physical path = C:\website1\ , appid = /LM/W3SVC/2/ROOT)
- admin application (physical path = C:\website1\admin , appid = /LM/W3SVC/2/ADMIN)
"Top level files hash"
Calculate the combined hash of (machine.config, web.config,…)
If hash is changed (some configs are changed) then delete all file in "code gen dir" (later rebuild everything)
Besides, the file hash\hash.web is monitored in realtime, if hash is changed then shutdown current AppDomain
Load all assembly in this file; find and run method with PreApplicationStartMethodAttribute
This is for initializing something before apppool running.
That's is the most important part. The cache key for /index.aspx is cdcab7d2 (w3wp.exe will find the cache file index.aspx.cdcab7d2.compiled in "code gen dir" folder to load information - assembly, type,...)
Here is the algorithm to generate cache key for a virtual path:
Now based on these concepts, we have some possible attack vectors:
- Attack01 - Stealthy webshell backdoor
- Attack02 - Support Arbitrary File Read & Unrestricted File Upload in a hardening server
- Attack03 - Bypass Apppool Isolation
- Attack04 - Bypass URL Filtering
Attack01 - Stealthy webshell backdoor
Remember the cache file
Hacker can upload a malicious dll in this folder and change the assembly and type property to hijack the normal function.
Hacker don't need to touch and change anything in webroot folder (C:/website1).
I have developed a tool makebackdoor.ps1 to automate this process.
- Find a normal un-necessary aspx file: /about.aspx
- Hijack compiled aspx: powershell -File makebackdoor.ps1 -virtualPath /about.aspx
- Access http://victim.com/about.aspx
This backdoor allow attacker to bypass:
- Directory monitoring
- Webshell scanner
- Access log machine learning
- And hard to forensic
Attack02 - Support Arbitrary File Read & Unrestricted File Upload in a hardening server
The basic idea is if you cannot read or write in webroot folder, you can read or write in the cache folder.
For example, if attacker have unrestricted file upload bug but the server disallow write permission in C:/website1/ so attacker cannot write a webshell in that folder. Attacker could think to write into the cache folder.
Another example, a few application use the pre-compiled source code and turn off the auto-compile options in production, so attacker can upload a webshell but the webshell is not compiled when it's accessed. Attacker could also think to write into the cache folder.
The hard part is to calculate the cache folder path, you need to know the physical path and appid of an application. One default is Root Application of Default WebSite (physical path = C:\inetpub\wwwroot\ and appid = /LM/W3SVC/1/ROOT)
I don't have any real case for this attack. Hope to see this attack in the future.
Attack03 - Bypass Apppool Isolation
In some cases, there are many websites in the same IIS server (for example, shared hosting)
I ask myself if a website could attack another one?
This is the permission of folder C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\
The problem is:
Pay attention that all ApplicationPoolIdentity belongs to BUILTIN\IIS_IUSERS. So any apppool account could modify or delete content in the cache folder of another account.
Here is the attack I do in some Plesk based shared hosting services:
I reported this issue to MSRC. And they did not consider this as a vulnerability. They have a guide for this risk.
And I reported to Plesk, they confirmed this bug and fix it.
But I think another shared hosting environment could be vulnerable too. I didn't check all of them. I only test for Plesk.
Attack04 - Bypass URL Filtering
The idea is cache key duplicate. Remember the cache key generation algorithm. It returns 8 hex characters (4 bytes)
The maximum unsigned 4 bytes is 4,294,967,295
The number is quite big but it is still easy to have a collision.
Here is some examples:
If some WAF block you at /admin/index.aspx, you can access at /a583524842/index.aspx
However, this attack vector didn't work anymore because Microsoft patched it in CVE-2020-1476
Here is the advisory: https://lab.viettelcybersecurity.com/advisories/VCSA-12