mirror of
https://github.com/HackTricks-wiki/hacktricks-cloud.git
synced 2025-12-12 07:40:49 -08:00
Translated ['src/pentesting-cloud/aws-security/aws-privilege-escalation/
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -34,3 +34,4 @@ Temporary Items
|
||||
book
|
||||
book/*
|
||||
hacktricks-preprocessor.log
|
||||
hacktricks-preprocessor-error.log
|
||||
|
||||
@@ -7,7 +7,14 @@ from os import path
|
||||
from urllib.request import urlopen, Request
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(filename='hacktricks-preprocessor.log', filemode='w', encoding='utf-8', level=logging.DEBUG)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
handler = logging.FileHandler(filename='hacktricks-preprocessor.log', mode='w', encoding='utf-8')
|
||||
handler.setLevel(logging.DEBUG)
|
||||
logger.addHandler(handler)
|
||||
|
||||
handler2 = logging.FileHandler(filename='hacktricks-preprocessor-error.log', mode='w', encoding='utf-8')
|
||||
handler2.setLevel(logging.ERROR)
|
||||
logger.addHandler(handler2)
|
||||
|
||||
|
||||
def findtitle(search ,obj, key, path=(),):
|
||||
@@ -45,19 +52,29 @@ def ref(matchobj):
|
||||
try:
|
||||
if href.endswith("/"):
|
||||
href = href+"README.md" # Fix if ref points to a folder
|
||||
chapter, _path = findtitle(href, book, "source_path")
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
title = chapter['name']
|
||||
if "#" in href:
|
||||
chapter, _path = findtitle(href.split("#")[0], book, "source_path")
|
||||
title = " ".join(href.split("#")[1].split("-")).title()
|
||||
logger.debug(f'Ref has # using title: {title}')
|
||||
else:
|
||||
chapter, _path = findtitle(href, book, "source_path")
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
title = chapter['name']
|
||||
except Exception as e:
|
||||
try:
|
||||
dir = path.dirname(current_chapter['source_path'])
|
||||
logger.debug(f'Error getting chapter title: {href} trying with relative path {path.normpath(path.join(dir,href))}')
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href)), book, "source_path")
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
title = chapter['name']
|
||||
if "#" in href:
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
title = " ".join(href.split("#")[1].split("-")).title()
|
||||
logger.debug(f'Ref has # using title: {title}')
|
||||
else:
|
||||
chapter, _path = findtitle(path.normpath(path.join(dir,href.split('#')[0])), book, "source_path")
|
||||
title = chapter["name"]
|
||||
logger.debug(f'Recursive title search result: {chapter["name"]}')
|
||||
except Exception as e:
|
||||
logger.debug(f'Error getting chapter title: {path.normpath(path.join(dir,href))}')
|
||||
print(f'Error getting chapter title: {path.normpath(path.join(dir,href))}')
|
||||
logger.debug(e)
|
||||
logger.error(f'Error getting chapter title: {path.normpath(path.join(dir,href))}')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -85,13 +102,11 @@ def files(matchobj):
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(e)
|
||||
logger.debug(f'Error searching file: {href}')
|
||||
print(f'Error searching file: {href}')
|
||||
logger.error(f'Error searching file: {href}')
|
||||
sys.exit(1)
|
||||
|
||||
if title=="":
|
||||
logger.debug(f'Error searching file: {href}')
|
||||
print(f'Error searching file: {href}')
|
||||
logger.error(f'Error searching file: {href}')
|
||||
sys.exit(1)
|
||||
|
||||
template = f"""<a class="content_ref" href="/files/{href}"><span class="content_ref_label">{title}</span></a>"""
|
||||
@@ -134,10 +149,11 @@ if __name__ == '__main__':
|
||||
for chapter in iterate_chapters(book['sections']):
|
||||
logger.debug(f"Chapter: {chapter['path']}")
|
||||
current_chapter = chapter
|
||||
regex = r'{{[\s]*#ref[\s]*}}(?:\n)?([^\\\n]*)(?:\n)?{{[\s]*#endref[\s]*}}'
|
||||
# regex = r'{{[\s]*#ref[\s]*}}(?:\n)?([^\\\n]*)(?:\n)?{{[\s]*#endref[\s]*}}'
|
||||
regex = r'{{[\s]*#ref[\s]*}}(?:\n)?([^\\\n#]*(?:#(.*))?)(?:\n)?{{[\s]*#endref[\s]*}}'
|
||||
new_content = re.sub(regex, ref, chapter['content'])
|
||||
regex = r'{{[\s]*#file[\s]*}}(?:\n)?([^\\\n]*)(?:\n)?{{[\s]*#endfile[\s]*}}'
|
||||
new_content = re.sub(regex, files, chapter['content'])
|
||||
new_content = re.sub(regex, files, new_content)
|
||||
new_content = add_read_time(new_content)
|
||||
chapter['content'] = new_content
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
]
|
||||
}
|
||||
```
|
||||
그리고 하이재킹은 **템플릿이 버킷에 업로드되는 순간부터** **템플릿이 배포되는 순간까지의 작은 시간 창** 때문에 가능합니다. 공격자는 자신의 계정에 **lambda function**을 생성하여 **버킷 알림이 전송될 때 트리거**되도록 하고, **버킷**의 **내용**을 **하이재킹**할 수 있습니다.
|
||||
그리고 하이재킹이 가능한 이유는 **템플릿이 버킷에 업로드되는 순간부터** **템플릿이 배포되는 순간까지의 작은 시간 창**이 있기 때문입니다. 공격자는 자신의 계정에 **lambda function**을 생성하여 **버킷 알림이 전송될 때 트리거**되도록 할 수 있으며, **버킷**의 **내용**을 **하이재킹**할 수 있습니다.
|
||||
|
||||
.png>)
|
||||
|
||||
@@ -54,17 +54,17 @@ Pacu 모듈 [`cfn__resouce_injection`](https://github.com/RhinoSecurityLabs/pacu
|
||||
|
||||
[terraform](https://cloud.hacktricks.wiki/en/pentesting-ci-cd/terraform-security.html) 상태 파일이 클라우드 제공자의 블롭 스토리지에 저장되는 것은 매우 일반적입니다. 예를 들어 AWS S3. 상태 파일의 파일 접미사는 `.tfstate`이며, 버킷 이름은 종종 terraform 상태 파일을 포함하고 있음을 나타냅니다. 일반적으로 모든 AWS 계정에는 상태 파일을 저장하는 하나의 버킷이 있습니다. 이 상태 파일은 계정의 상태를 보여줍니다. 또한 실제 계정에서는 거의 모든 개발자가 `s3:*` 권한을 가지고 있으며, 때로는 비즈니스 사용자도 `s3:Put*` 권한을 가집니다.
|
||||
|
||||
따라서 이러한 파일에 대해 나열된 권한이 있는 경우, `terraform`의 권한으로 파이프라인에서 RCE를 얻을 수 있는 공격 벡터가 있습니다. 대부분의 경우 `AdministratorAccess`가 되어 클라우드 계정의 관리자가 됩니다. 또한 이 벡터를 사용하여 `terraform`이 합법적인 리소스를 삭제하도록 하여 서비스 거부 공격을 수행할 수 있습니다.
|
||||
따라서 이러한 파일에 대해 나열된 권한이 있는 경우, `terraform`의 권한으로 파이프라인에서 RCE를 얻을 수 있는 공격 벡터가 있습니다. 대부분의 경우 `AdministratorAccess`로 클라우드 계정의 관리자가 됩니다. 또한 이 벡터를 사용하여 `terraform`이 합법적인 리소스를 삭제하도록 하여 서비스 거부 공격을 수행할 수 있습니다.
|
||||
|
||||
직접 사용할 수 있는 익스플로잇 코드는 *Terraform Security* 페이지의 *Abusing Terraform State Files* 섹션의 설명을 따르세요:
|
||||
*Terraform Security* 페이지의 *Abusing Terraform State Files* 섹션에 있는 설명을 따라 직접 사용할 수 있는 익스플로잇 코드를 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
terraform-security.md#abusing-terraform-state-files
|
||||
pentesting-ci-cd/terraform-security.md#abusing-terraform-state-files
|
||||
{{#endref}}
|
||||
|
||||
### `s3:PutBucketPolicy`
|
||||
|
||||
공격자는 **같은 계정에서** 있어야 하며, 그렇지 않으면 `The specified method is not allowed` 오류가 발생합니다. 이 권한을 가진 공격자는 자신에게 버킷에 대한 더 많은 권한을 부여하여 읽기, 쓰기, 수정, 삭제 및 버킷을 노출할 수 있습니다.
|
||||
공격자는 **같은 계정에서** 있어야 하며, 그렇지 않으면 `The specified method is not allowed` 오류가 발생합니다. 이 권한을 가진 공격자는 자신에게 더 많은 권한을 부여하여 버킷에 대한 읽기, 쓰기, 수정, 삭제 및 노출을 허용할 수 있습니다.
|
||||
```bash
|
||||
# Update Bucket policy
|
||||
aws s3api put-bucket-policy --policy file:///root/policy.json --bucket <bucket-name>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
Azure App 서비스에 대한 자세한 정보는 다음을 확인하세요:
|
||||
|
||||
{{#ref}}
|
||||
../az-services/az-app-service.md
|
||||
../az-services/az-app-services.md
|
||||
{{#endref}}
|
||||
|
||||
### Microsoft.Web/sites/publish/Action, Microsoft.Web/sites/basicPublishingCredentialsPolicies/read, Microsoft.Web/sites/config/read, Microsoft.Web/sites/read
|
||||
@@ -35,9 +35,9 @@ ssh root@127.0.0.1 -p 39895
|
||||
- **애플리케이션 디버깅**:
|
||||
1. VScode에 Azure 확장을 설치합니다.
|
||||
2. Azure 계정으로 확장에 로그인합니다.
|
||||
3. 구독 내 모든 앱 서비스를 나열합니다.
|
||||
4. 디버깅할 앱 서비스를 선택하고 마우스 오른쪽 버튼을 클릭한 후 "디버깅 시작"을 선택합니다.
|
||||
5. 앱에 디버깅이 활성화되어 있지 않으면, 확장이 이를 활성화하려고 시도하지만, 귀하의 계정은 이를 수행하기 위해 `Microsoft.Web/sites/config/write` 권한이 필요합니다.
|
||||
3. 구독 내 모든 App 서비스를 나열합니다.
|
||||
4. 디버깅할 App 서비스를 선택하고, 마우스 오른쪽 버튼을 클릭한 후 "디버깅 시작"을 선택합니다.
|
||||
5. 앱에 디버깅이 활성화되어 있지 않으면, 확장이 이를 활성화하려고 시도하지만, 귀하의 계정은 `Microsoft.Web/sites/config/write` 권한이 필요합니다.
|
||||
|
||||
### SCM 자격 증명 얻기 및 기본 인증 활성화
|
||||
|
||||
@@ -94,11 +94,11 @@ az webapp deployment list-publishing-profiles --name <app-name> --resource-group
|
||||
}
|
||||
]
|
||||
```
|
||||
사용자 이름은 항상 동일하다는 점에 유의하세요(FTP에서는 앱 이름이 앞에 추가됨). 그러나 모든 경우에 대해 비밀번호는 동일합니다.
|
||||
**사용자 이름은 항상 동일합니다** (FTP에서는 앱 이름이 앞에 추가됨) 하지만 **비밀번호는 모두 동일합니다**.
|
||||
|
||||
또한, SCM URL은 `<app-name>.scm.azurewebsites.net`입니다.
|
||||
또한, **SCM URL은 `<app-name>.scm.azurewebsites.net`**입니다.
|
||||
|
||||
- 권한 **`Microsoft.Web/sites/config/list/action`**은 다음을 호출할 수 있습니다:
|
||||
- 권한 **`Microsoft.Web/sites/config/list/action`**은 호출할 수 있습니다:
|
||||
```bash
|
||||
az webapp deployment list-publishing-credentials --name <app-name> --resource-group <res-group>
|
||||
# Example output
|
||||
@@ -131,8 +131,7 @@ az webapp deployment user set \
|
||||
> [!WARNING]
|
||||
> 모든 사용자가 이전 명령을 호출하여 자신의 자격 증명을 구성할 수 있지만, 사용자가 SCM 또는 FTP에 액세스할 수 있는 충분한 권한이 없으면 자격 증명이 작동하지 않습니다.
|
||||
|
||||
|
||||
- 이러한 자격 증명이 **REDACTED**로 표시되면, 이는 **SCM 기본 인증 옵션을 활성화해야 하기 때문이며**, 이를 위해 두 번째 권한(`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write`)이 필요합니다:
|
||||
- 자격 증명이 **REDACTED**로 표시되면, 이는 **SCM 기본 인증 옵션을 활성화해야 하기 때문이며**, 이를 위해 두 번째 권한(`Microsoft.Web/sites/basicPublishingCredentialsPolicies/write`)이 필요합니다:
|
||||
```bash
|
||||
# Enable basic authentication for SCM
|
||||
az rest --method PUT \
|
||||
@@ -206,7 +205,7 @@ curl -X PUT \
|
||||
```
|
||||
### Microsoft.Web/sites/write, Microsoft.Web/sites/read, Microsoft.ManagedIdentity/userAssignedIdentities/assign/action
|
||||
|
||||
이 권한은 **관리되는 ID**를 App 서비스에 할당할 수 있게 하므로, 이전에 App 서비스가 손상된 경우 공격자가 App 서비스에 새로운 관리되는 ID를 할당하고 **권한을 상승**시킬 수 있습니다.
|
||||
이 권한은 **관리형 ID**를 App 서비스에 할당할 수 있게 하므로, 이전에 App 서비스가 침해된 경우 공격자가 App 서비스에 새로운 관리형 ID를 할당하고 **권한을 상승**시킬 수 있습니다.
|
||||
```bash
|
||||
az webapp identity assign --name <app-name> --resource-group <res-group> --identities /subscriptions/<subcripttion-id>/resourceGroups/<res_group>/providers/Microsoft.ManagedIdentity/userAssignedIdentities/<managed-identity-name>
|
||||
```
|
||||
@@ -226,7 +225,7 @@ az rest --method GET \
|
||||
```
|
||||
이 명령은 Github, Bitbucket, Dropbox 및 OneDrive에 대한 토큰을 반환합니다.
|
||||
|
||||
여기 토큰을 확인하기 위한 몇 가지 명령 예가 있습니다:
|
||||
여기 토큰을 확인하기 위한 몇 가지 명령 예제가 있습니다:
|
||||
```bash
|
||||
# GitHub – List Repositories
|
||||
curl -H "Authorization: token <token>" \
|
||||
@@ -249,29 +248,29 @@ curl -H "Authorization: Bearer <token>" \
|
||||
-H "Accept: application/json" \
|
||||
https://graph.microsoft.com/v1.0/me/drive/root/children
|
||||
```
|
||||
### Update App Code from the source
|
||||
### 소스에서 앱 코드 업데이트
|
||||
|
||||
- If the configured source is a third-party provider like Github, BitBucket or an Azure Repository, you can **update the code** of the App service by compromising the source code in the repository.
|
||||
- If the app is configured using a **remote git repository** (with username and password), it's possible to get the **URL and basic auth credentials** to clone and push changes with:
|
||||
- Using the permission **`Microsoft.Web/sites/sourcecontrols/read`**: `az webapp deployment source show --name <app-name> --resource-group <res-group>`
|
||||
- Using the permission **`Microsoft.Web/sites/config/list/action`**:
|
||||
- 구성된 소스가 Github, BitBucket 또는 Azure Repository와 같은 제3자 제공자인 경우, 리포지토리의 소스 코드를 손상시켜 **앱 서비스의 코드를 업데이트**할 수 있습니다.
|
||||
- 앱이 **원격 git 리포지토리**(사용자 이름 및 비밀번호 포함)를 사용하도록 구성된 경우, 다음을 통해 **URL 및 기본 인증 자격 증명**을 얻어 클론하고 변경 사항을 푸시할 수 있습니다:
|
||||
- 권한 **`Microsoft.Web/sites/sourcecontrols/read`** 사용: `az webapp deployment source show --name <app-name> --resource-group <res-group>`
|
||||
- 권한 **`Microsoft.Web/sites/config/list/action`** 사용:
|
||||
- `az webapp deployment list-publishing-credentials --name <app-name> --resource-group <res-group>`
|
||||
- `az rest --method POST --url "https://management.azure.com/subscriptions/<subscription-id>/resourceGroups/<res-group>/providers/Microsoft.Web/sites/<app-name>/config/metadata/list?api-version=2022-03-01" --resource "https://management.azure.com"`
|
||||
- If the app is configured to use a **local git repository**, it's possible to **clone the repository** and **push changes** to it:
|
||||
- Using the permission **`Microsoft.Web/sites/sourcecontrols/read`**: You can get the URL of the git repo with `az webapp deployment source show --name <app-name> --resource-group <res-group>`, but it's going to be the same as the the SCM URL of the app with the path `/<app-name>.git` (e.g. `https://pythonwebapp-audeh9f5fzeyhhed.scm.canadacentral-01.azurewebsites.net:443/pythonwebapp.git`).
|
||||
- To get the SCM credential you need the permission:
|
||||
- **`Microsoft.Web/sites/publishxml/action`**: Then run `az webapp deployment list-publishing-profiles --resource-group <res-group> -n <name>`.
|
||||
- **`Microsoft.Web/sites/config/list/action`**: Then run `az webapp deployment list-publishing-credentials --name <name> --resource-group <res-group>`
|
||||
- 앱이 **로컬 git 리포지토리**를 사용하도록 구성된 경우, **리포지토리를 클론하고 변경 사항을 푸시**할 수 있습니다:
|
||||
- 권한 **`Microsoft.Web/sites/sourcecontrols/read`** 사용: `az webapp deployment source show --name <app-name> --resource-group <res-group>`로 git 리포지토리의 URL을 얻을 수 있지만, 이는 앱의 SCM URL과 동일하며 경로는 `/<app-name>.git`입니다 (예: `https://pythonwebapp-audeh9f5fzeyhhed.scm.canadacentral-01.azurewebsites.net:443/pythonwebapp.git`).
|
||||
- SCM 자격 증명을 얻으려면 다음 권한이 필요합니다:
|
||||
- **`Microsoft.Web/sites/publishxml/action`**: 그런 다음 `az webapp deployment list-publishing-profiles --resource-group <res-group> -n <name>`을 실행합니다.
|
||||
- **`Microsoft.Web/sites/config/list/action`**: 그런 다음 `az webapp deployment list-publishing-credentials --name <name> --resource-group <res-group>`을 실행합니다.
|
||||
|
||||
> [!WARNING]
|
||||
> Note that having the permission `Microsoft.Web/sites/config/list/action` and the SCM credentials it's always possible to deploy into a webapp (even if it was configured to use a third-party provider) as mentioned in a previous section.
|
||||
> 권한 `Microsoft.Web/sites/config/list/action`과 SCM 자격 증명을 보유하면, 이전 섹션에서 언급한 바와 같이 웹앱에 배포하는 것이 항상 가능합니다 (제3자 제공자를 사용하도록 구성된 경우에도).
|
||||
|
||||
> [!WARNING]
|
||||
> Note that having the permissions below it's also **possible to execute an arbitrary container** even if the webapp was configured differently.
|
||||
> 아래 권한을 보유하면 웹앱이 다르게 구성되었더라도 **임의의 컨테이너를 실행하는 것도 가능합니다**.
|
||||
|
||||
### `Microsoft.Web/sites/config/Write`, `Microsoft.Web/sites/config/Read`, `Microsoft.Web/sites/config/list/Action`, `Microsoft.Web/sites/Read`
|
||||
|
||||
이것은 웹앱에서 사용되는 **컨테이너를 수정할 수 있는** 권한 세트입니다. 공격자는 이를 악용하여 웹앱이 악성 컨테이너를 실행하도록 만들 수 있습니다.
|
||||
이 권한 세트는 웹앱에서 사용되는 **컨테이너를 수정**할 수 있게 해줍니다. 공격자는 이를 악용하여 웹앱이 악성 컨테이너를 실행하도록 만들 수 있습니다.
|
||||
```bash
|
||||
az webapp config container set \
|
||||
--name <app-name> \
|
||||
|
||||
@@ -2,79 +2,79 @@
|
||||
|
||||
{{#include ../../../banners/hacktricks-training.md}}
|
||||
|
||||
## 기본 정보
|
||||
## Basic Information
|
||||
|
||||
**Azure Function Apps**는 **서버리스 컴퓨트 서비스**로, 기본 인프라를 관리하지 않고도 **함수**라고 불리는 작은 코드 조각을 실행할 수 있게 해줍니다. 이들은 **HTTP 요청, 타이머 또는 Blob Storage나 Event Hubs와 같은 다른 Azure 서비스의 이벤트**와 같은 다양한 트리거에 응답하여 코드를 실행하도록 설계되었습니다. Function Apps는 C#, Python, JavaScript, Java 등 여러 프로그래밍 언어를 지원하여 **이벤트 기반 애플리케이션**, 워크플로 자동화 또는 서비스 통합을 구축하는 데 유용합니다. 일반적으로 코드가 실행될 때 사용된 컴퓨트 시간에 대해서만 비용을 지불하므로 비용 효율적입니다.
|
||||
|
||||
> [!NOTE]
|
||||
> **Functions는 App Services의 하위 집합**이므로, 여기서 논의된 많은 기능은 Azure Apps(`webapp` in cli)로 생성된 애플리케이션에서도 사용됩니다.
|
||||
|
||||
### 다양한 요금제
|
||||
### Different Plans
|
||||
|
||||
- **Flex Consumption Plan**: 수요에 따라 함수 인스턴스를 추가하거나 제거하는 **동적 이벤트 기반 스케일링**을 제공하며, 사용한 만큼만 지불하는 요금제를 제공합니다. **가상 네트워킹** 및 **사전 프로비저닝된 인스턴스**를 지원하여 콜드 스타트를 줄여주며, 컨테이너 지원이 필요하지 않은 **변동 작업 부하**에 적합합니다.
|
||||
- **Traditional Consumption Plan**: 기본 서버리스 옵션으로, **함수가 실행될 때만 컴퓨트 리소스에 대해 지불**합니다. 수신 이벤트에 따라 자동으로 스케일링되며 **콜드 스타트 최적화**가 포함되어 있지만, 컨테이너 배포는 지원하지 않습니다. 자동 스케일링이 필요한 **간헐적 작업 부하**에 이상적입니다.
|
||||
- **Premium Plan**: **일관된 성능**을 위해 설계되었으며, 콜드 스타트를 없애기 위해 **사전 예열된 작업자**를 제공합니다. **연장된 실행 시간, 가상 네트워킹**을 제공하며, **사용자 정의 Linux 이미지**를 지원하여 높은 성능과 고급 기능이 필요한 **미션 크리티컬 애플리케이션**에 적합합니다.
|
||||
- **Dedicated Plan**: 예측 가능한 청구가 가능한 전용 가상 머신에서 실행되며, 수동 또는 자동 스케일링을 지원합니다. 동일한 요금제에서 여러 앱을 실행할 수 있으며, **컴퓨트 격리**를 제공하고 App Service Environments를 통해 **안전한 네트워크 액세스**를 보장하여 일관된 리소스 할당이 필요한 **장기 실행 애플리케이션**에 이상적입니다.
|
||||
- **Dedicated Plan**: 예측 가능한 청구가 가능한 전용 가상 머신에서 실행되며, 수동 또는 자동 스케일링을 지원합니다. 동일한 계획에서 여러 앱을 실행할 수 있으며, **컴퓨트 격리**를 제공하고 App Service Environments를 통해 **안전한 네트워크 액세스**를 보장하여 일관된 리소스 할당이 필요한 **장기 실행 애플리케이션**에 이상적입니다.
|
||||
- **Container Apps**: 관리되는 환경에서 **컨테이너화된 함수 앱**을 배포할 수 있으며, 마이크로서비스 및 API와 함께 사용할 수 있습니다. 사용자 정의 라이브러리, 레거시 앱 마이그레이션 및 **GPU 처리**를 지원하여 Kubernetes 클러스터 관리를 없애줍니다. **이벤트 기반, 확장 가능한 컨테이너화된 애플리케이션**에 적합합니다.
|
||||
|
||||
### **스토리지 버킷**
|
||||
### **Storage Buckets**
|
||||
|
||||
컨테이너화되지 않은 새로운 Function App을 생성할 때, **코드 및 기타 Function 관련 데이터는 스토리지 계정에 저장됩니다**. 기본적으로 웹 콘솔은 코드를 저장하기 위해 함수당 새 스토리지 계정을 생성합니다.
|
||||
컨테이너화되지 않은 새로운 Function App을 생성할 때 (코드를 실행할 수 있도록 제공하는 경우), **코드 및 기타 Function 관련 데이터는 Storage 계정에 저장됩니다**. 기본적으로 웹 콘솔은 코드를 저장하기 위해 함수당 새 Storage 계정을 생성합니다.
|
||||
|
||||
또한, 버킷 내의 코드를 수정하면 (저장될 수 있는 다양한 형식에서) **앱의 코드가 새 코드로 수정되어 다음에 함수가 호출될 때 실행됩니다**.
|
||||
또한, 버킷 내의 코드를 수정하면 (저장될 수 있는 다양한 형식에서), **앱의 코드는 새로운 코드로 수정되어 다음에 함수가 호출될 때 실행됩니다**.
|
||||
|
||||
> [!CAUTION]
|
||||
> 공격자의 관점에서 매우 흥미로운 점은 **이 버킷에 대한 쓰기 권한**이 공격자가 **코드를 손상시키고 Function App 내의 관리되는 ID에 대한 권한을 상승시킬 수 있게 해준다는 것입니다.**
|
||||
> 공격자의 관점에서 매우 흥미로운 점은 **이 버킷에 대한 쓰기 권한**이 있으면 공격자가 **코드를 손상시키고 Function App 내의 관리되는 ID에 대한 권한을 상승시킬 수 있다는 점입니다**.
|
||||
>
|
||||
> 이에 대한 자세한 내용은 **권한 상승 섹션**에서 다룹니다.
|
||||
> 이에 대한 자세한 내용은 **권한 상승 섹션**에서 확인할 수 있습니다.
|
||||
|
||||
또한, **`azure-webjobs-secrets`** 컨테이너 내의 스토리지 계정에서 **마스터 및 함수 키**를 찾는 것도 가능합니다. 이 키는 **`<app-name>`** 폴더 내의 JSON 파일에서 찾을 수 있습니다.
|
||||
또한, **`azure-webjobs-secrets`** 컨테이너 내의 Storage 계정에서 **마스터 및 함수 키**를 찾는 것도 가능합니다. 이 키는 **`<app-name>`** 폴더 내의 JSON 파일에서 찾을 수 있습니다.
|
||||
|
||||
Functions는 또한 코드를 원격 위치에 저장할 수 있으며, 그 URL을 지정하기만 하면 됩니다.
|
||||
|
||||
### 네트워킹
|
||||
### Networking
|
||||
|
||||
HTTP 트리거를 사용하여:
|
||||
HTTP 트리거를 사용할 때:
|
||||
|
||||
- **인터넷의 모든 사용자에게 함수에 대한 액세스를 제공**하거나 IAM 기반으로 액세스를 제공할 수 있습니다. 이 액세스를 제한하는 것도 가능합니다.
|
||||
- **내부 네트워크(VPC)**에서 Function App에 대한 액세스를 **제공하거나 제한**할 수 있습니다.
|
||||
|
||||
> [!CAUTION]
|
||||
> 공격자의 관점에서 매우 흥미로운 점은 취약한 Function이 인터넷에 노출된 경우 **내부 네트워크로 피벗할 수 있는 가능성이 있다는 것입니다.**
|
||||
> 공격자의 관점에서 매우 흥미로운 점은 취약한 Function이 인터넷에 노출된 경우 **내부 네트워크로 피벗할 수 있는 가능성이 있다는 점입니다**.
|
||||
|
||||
### **Function App 설정 및 환경 변수**
|
||||
### **Function App Settings & Environment Variables**
|
||||
|
||||
앱 내에서 환경 변수를 구성할 수 있으며, 이 변수는 민감한 정보를 포함할 수 있습니다. 또한 기본적으로 **`AzureWebJobsStorage`** 및 **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`**(기타 포함)과 같은 env 변수가 생성됩니다. 이들은 **애플리케이션 데이터가 포함된 스토리지 계정을 완전 권한으로 제어할 수 있는 계정 키를 포함**하고 있어 특히 흥미롭습니다. 이러한 설정은 스토리지 계정에서 코드를 실행하는 데에도 필요합니다.
|
||||
앱 내에서 환경 변수를 구성할 수 있으며, 이 변수는 민감한 정보를 포함할 수 있습니다. 또한 기본적으로 **`AzureWebJobsStorage`** 및 **`WEBSITE_CONTENTAZUREFILECONNECTIONSTRING`** (기타 포함)과 같은 env 변수가 생성됩니다. 이들은 **애플리케이션 데이터가 포함된 Storage 계정을 완전한 권한으로 제어하는 계정 키를 포함하고 있기 때문에 특별히 흥미롭습니다**. 이러한 설정은 Storage 계정에서 코드를 실행하는 데에도 필요합니다.
|
||||
|
||||
이러한 env 변수 또는 구성 매개변수는 Function이 코드를 실행하는 방식을 제어합니다. 예를 들어 **`WEBSITE_RUN_FROM_PACKAGE`**가 존재하면 애플리케이션 코드가 위치한 URL을 나타냅니다.
|
||||
이러한 env 변수 또는 구성 매개변수는 함수가 코드를 실행하는 방식을 제어합니다. 예를 들어 **`WEBSITE_RUN_FROM_PACKAGE`**가 존재하면 애플리케이션 코드가 위치한 URL을 나타냅니다.
|
||||
|
||||
### **Function Sandbox**
|
||||
|
||||
리눅스 샌드박스 내에서 소스 코드는 **`/home/site/wwwroot`**의 **`function_app.py`**(Python 사용 시)에 위치하며, 코드를 실행하는 사용자는 **`app`**(sudo 권한 없음)입니다.
|
||||
리눅스 샌드박스 내에서 소스 코드는 **`/home/site/wwwroot`**의 **`function_app.py`** 파일에 위치하며 (Python을 사용하는 경우), 코드를 실행하는 사용자는 **`app`**입니다 (sudo 권한 없음).
|
||||
|
||||
**Windows** 함수에서 NodeJS를 사용하는 경우 코드는 **`C:\home\site\wwwroot\HttpTrigger1\index.js`**에 위치하며, 사용자 이름은 **`mawsFnPlaceholder8_f_v4_node_20_x86`**이고, **그룹**은 `Mandatory Label\High Mandatory Level Label`, `Everyone`, `BUILTIN\Users`, `NT AUTHORITY\INTERACTIVE`, `CONSOLE LOGON`, `NT AUTHORITY\Authenticated Users`, `NT AUTHORITY\This Organization`, `BUILTIN\IIS_IUSRS`, `LOCAL`, `10-30-4-99\Dwas Site Users`의 일부입니다.
|
||||
**Windows** 함수에서 NodeJS를 사용하는 경우 코드는 **`C:\home\site\wwwroot\HttpTrigger1\index.js`**에 위치하며, 사용자 이름은 **`mawsFnPlaceholder8_f_v4_node_20_x86`**이고 **그룹**의 일부입니다: `Mandatory Label\High Mandatory Level Label`, `Everyone`, `BUILTIN\Users`, `NT AUTHORITY\INTERACTIVE`, `CONSOLE LOGON`, `NT AUTHORITY\Authenticated Users`, `NT AUTHORITY\This Organization`, `BUILTIN\IIS_IUSRS`, `LOCAL`, `10-30-4-99\Dwas Site Users`.
|
||||
|
||||
### **관리되는 ID 및 메타데이터**
|
||||
### **Managed Identities & Metadata**
|
||||
|
||||
[**VMs**](vms/)와 마찬가지로 Functions는 **시스템 할당** 및 **사용자 할당**의 2가지 유형의 **Managed Identities**를 가질 수 있습니다.
|
||||
[**VMs**](vms/index.html)와 마찬가지로, Functions는 **시스템 할당** 및 **사용자 할당**의 두 가지 유형의 **Managed Identities**를 가질 수 있습니다.
|
||||
|
||||
**시스템 할당**된 ID는 **해당 함수**만 사용할 수 있는 관리되는 ID이며, **사용자 할당**된 관리되는 ID는 **다른 Azure 서비스가 사용할 수 있는 관리되는 ID**입니다.
|
||||
**시스템 할당**된 것은 **해당 함수**만 사용할 수 있는 관리되는 ID이며, **사용자 할당**된 관리되는 ID는 **다른 Azure 서비스가 사용할 수 있는 관리되는 ID**입니다.
|
||||
|
||||
> [!NOTE]
|
||||
> [**VMs**](vms/)와 마찬가지로 Functions는 **1개의 시스템 할당** 관리되는 ID와 **여러 사용자 할당** 관리되는 ID를 가질 수 있으므로, 함수를 손상시키면 모든 ID를 찾는 것이 항상 중요합니다. 하나의 Function에서 여러 관리되는 ID로 권한을 상승시킬 수 있습니다.
|
||||
> [**VMs**](vms/index.html)와 마찬가지로, Functions는 **1개의 시스템 할당** 관리되는 ID와 **여러 사용자 할당** 관리되는 ID를 가질 수 있으므로, 함수를 손상시키면 모든 관리되는 ID를 찾는 것이 항상 중요합니다. 하나의 Function에서 여러 관리되는 ID로 권한을 상승시킬 수 있습니다.
|
||||
>
|
||||
> 시스템 관리 ID가 사용되지 않고 하나 이상의 사용자 관리 ID가 함수에 연결된 경우 기본적으로 토큰을 얻을 수 없습니다.
|
||||
> 시스템 관리 ID가 사용되지 않고 하나 이상의 사용자 관리 ID가 함수에 연결된 경우, 기본적으로 토큰을 얻을 수 없습니다.
|
||||
|
||||
[**PEASS 스크립트**](https://github.com/peass-ng/PEASS-ng)를 사용하여 메타데이터 엔드포인트에서 기본 관리 ID의 토큰을 얻을 수 있습니다. 또는 다음과 같이 **수동으로** 얻을 수 있습니다:
|
||||
[**PEASS scripts**](https://github.com/peass-ng/PEASS-ng)를 사용하여 메타데이터 엔드포인트에서 기본 관리 ID의 토큰을 얻을 수 있습니다. 또는 다음과 같이 **수동으로** 얻을 수 있습니다:
|
||||
|
||||
{% embed url="https://book.hacktricks.xyz/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf#azure-vm" %}
|
||||
|
||||
함수가 연결된 **모든 관리 ID를 확인하는 방법**을 찾아야 합니다. 그렇지 않으면 메타데이터 엔드포인트는 **기본 ID만 사용**합니다(자세한 내용은 이전 링크를 참조).
|
||||
함수가 연결된 모든 Managed Identities를 **확인하는 방법을 찾아야 합니다**. 그렇지 않으면 메타데이터 엔드포인트는 **기본 ID만 사용합니다** (자세한 내용은 이전 링크를 확인하세요).
|
||||
|
||||
## 액세스 키
|
||||
## Access Keys
|
||||
|
||||
> [!NOTE]
|
||||
> 함수 호출에 대한 사용자 액세스를 부여하는 RBAC 권한이 없음을 유의하십시오. **함수 호출은 생성 시 선택된 트리거에 따라 달라지며, HTTP 트리거가 선택된 경우 **액세스 키**를 사용해야 할 수 있습니다.**
|
||||
> 함수 호출에 대한 사용자 액세스를 부여하는 RBAC 권한이 없음을 유의하세요. **함수 호출은 생성 시 선택된 트리거에 따라 달라지며, HTTP 트리거가 선택된 경우 **액세스 키**를 사용해야 할 수 있습니다**.
|
||||
|
||||
HTTP 트리거를 사용하여 함수 내에서 엔드포인트를 생성할 때, 함수 트리거에 필요한 **액세스 키 권한 수준**을 지정할 수 있습니다. 세 가지 옵션이 있습니다:
|
||||
|
||||
@@ -84,27 +84,27 @@ HTTP 트리거를 사용하여 함수 내에서 엔드포인트를 생성할 때
|
||||
|
||||
**키 유형:**
|
||||
|
||||
- **Function Keys:** 함수 키는 기본 또는 사용자 정의일 수 있으며, Function App 내의 **특정 함수 엔드포인트**에 대한 액세스를 독점적으로 부여하도록 설계되었습니다.
|
||||
- **Host Keys:** 호스트 키는 기본 또는 사용자 정의일 수 있으며, FUNCTION 액세스 수준으로 Function App 내의 **모든 함수 엔드포인트**에 대한 액세스를 제공합니다.
|
||||
- **Master Key:** 마스터 키(`_master`)는 모든 함수 엔드포인트에 대한 액세스를 포함하여 권한이 상승된 액세스를 제공하는 관리 키입니다. 이 **키는 취소할 수 없습니다.**
|
||||
- **System Keys:** 시스템 키는 **특정 확장에 의해 관리**되며, 내부 구성 요소에서 사용하는 웹훅 엔드포인트에 접근하는 데 필요합니다. 예를 들어, Event Grid 트리거 및 Durable Functions는 시스템 키를 사용하여 해당 API와 안전하게 상호작용합니다.
|
||||
- **Function Keys:** 함수 키는 기본 또는 사용자 정의일 수 있으며, Function App 내의 **특정 함수 엔드포인트**에만 접근을 허용하도록 설계되었습니다. 이를 통해 엔드포인트에 대한 보다 세밀한 접근 제어가 가능합니다.
|
||||
- **Host Keys:** 호스트 키는 기본 또는 사용자 정의일 수 있으며, **FUNCTION 접근 수준**으로 Function App 내의 **모든 함수 엔드포인트**에 접근을 제공합니다.
|
||||
- **Master Key:** 마스터 키(`_master`)는 모든 함수 엔드포인트에 대한 접근을 포함하여 **승격된 권한**을 제공하는 관리 키입니다. 이 **키는 취소할 수 없습니다.**
|
||||
- **System Keys:** 시스템 키는 **특정 확장에 의해 관리되며**, 내부 구성 요소에서 사용하는 웹훅 엔드포인트에 접근하는 데 필요합니다. 예를 들어, Event Grid 트리거 및 Durable Functions는 시스템 키를 사용하여 해당 API와 안전하게 상호작용합니다.
|
||||
|
||||
> [!TIP]
|
||||
> 키를 사용하여 함수 API 엔드포인트에 접근하는 예:
|
||||
>
|
||||
> `https://<function_uniq_name>.azurewebsites.net/api/<endpoint_name>?code=<access_key>`
|
||||
|
||||
### 기본 인증
|
||||
### Basic Authentication
|
||||
|
||||
App Services와 마찬가지로 Functions는 **SCM** 및 **FTP**에 연결하여 코드를 배포하기 위해 Azure에서 제공하는 **사용자 이름과 비밀번호가 포함된 URL**을 사용하여 기본 인증을 지원합니다. 이에 대한 자세한 내용은:
|
||||
App Services와 마찬가지로, Functions는 **SCM** 및 **FTP**에 연결하여 코드를 배포하기 위해 Azure에서 제공하는 **URL의 사용자 이름과 비밀번호**를 사용한 기본 인증을 지원합니다. 이에 대한 자세한 내용은:
|
||||
|
||||
{{#ref}}
|
||||
az-app-service.md
|
||||
az-app-services.md
|
||||
{{#endref}}
|
||||
|
||||
### Github 기반 배포
|
||||
### Github Based Deployments
|
||||
|
||||
함수가 Github 리포지토리에서 생성될 때 Azure 웹 콘솔은 **특정 리포지토리에서 자동으로 Github Workflow를 생성**할 수 있게 해주며, 이 리포지토리가 업데이트될 때마다 함수의 코드가 업데이트됩니다. 실제로 Python 함수에 대한 Github Action yaml은 다음과 같습니다:
|
||||
함수가 Github 리포지토리에서 생성될 때 Azure 웹 콘솔은 **특정 리포지토리에서 자동으로 Github Workflow를 생성**할 수 있도록 하여 이 리포지토리가 업데이트될 때마다 함수의 코드가 업데이트됩니다. 실제로 Python 함수에 대한 Github Action yaml은 다음과 같습니다:
|
||||
|
||||
<details>
|
||||
|
||||
@@ -192,10 +192,10 @@ package: ${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}
|
||||
```
|
||||
</details>
|
||||
|
||||
또한, **Managed Identity**가 생성되어 리포지토리의 Github Action이 이를 사용하여 Azure에 로그인할 수 있습니다. 이는 **Managed Identity**에 대해 Federated credential을 생성하여 **Issuer** `https://token.actions.githubusercontent.com`와 **Subject Identifier** `repo:<org-name>/<repo-name>:ref:refs/heads/<branch-name>`를 허용함으로써 이루어집니다.
|
||||
또한, **Managed Identity**가 생성되어 리포지토리의 Github Action이 이를 사용하여 Azure에 로그인할 수 있습니다. 이는 **Managed Identity**에 대해 **Issuer** `https://token.actions.githubusercontent.com`와 **Subject Identifier** `repo:<org-name>/<repo-name>:ref:refs/heads/<branch-name>`를 허용하는 Federated credential을 생성함으로써 이루어집니다.
|
||||
|
||||
> [!CAUTION]
|
||||
> 따라서 해당 리포지토리를 손상시키는 사람은 기능과 이에 연결된 Managed Identities를 손상시킬 수 있습니다.
|
||||
> 따라서, 해당 리포지토리를 손상시키는 사람은 기능과 이에 연결된 Managed Identities를 손상시킬 수 있습니다.
|
||||
|
||||
### Container Based Deployments
|
||||
|
||||
|
||||
Reference in New Issue
Block a user