본문 바로가기

DevOps/AWS

[AHSS 3주차] 웹 취약점 및 보안

cloudNet@ 팀의 가시다 님이 진행하는 AWS 보안 스터디 3주차 정리입니다.
AWS WAF Configuration A to Z workshop을 참고 했습니다.

 

먼저 AWS WAF에 대한 학습 및 실습을 진행하기 전에, 웹 취약점이란 무엇이며? 어떤 공격들이 있을까에 대한 질문으로 부터 

포스팅을 시작하겠습니다.

 

현업에서 제가 WAF에 대한 경험을 한적은 없지만, 개발 SI에서 일할때 보안성 심의를 받은적이 있습니다.

그때 sql injection이나, XSS (크로스 사이트 스크립팅 ) 기법에 대한 제가 개발한 어플리케이션의 심의를 받은적이 있기 때문에 

이때는 해당 보안성 심의에 대한 지엽적인 보완을 위해 코드 변경을 통해 보안성 심의를 통과했었는데,

 

WAF를 쓰면 이런 부분들을 전체적으로 보완할수 있다는 이야기를 들은적이 있습니다.

20년도에 보안성 심의를 받으면서 블로그에 제가 포스팅 한 내용들을 참고하셔도 좋을것 같습니다.

현재 제가 알기로는 저런 방법으로 지엽적인 코드 변경을 통해 보안성 심의를 대처하는것은 올바른 방법은 아니라고 알고 있습니다. 

 

조금만 체계적으로 일하는 조직만 되더라도 팀 또는 조직 단위로 보안 부분만을 커버링 하는 식으로 일을 하기 때문에, 제가 과거에 받았던 보안성 심의를 기억하면서 .. 아 나는 이렇게 했었지 정도로 경험했던 부분을 떠올리며, 조금 더 제대로 현업에서는 어떤 방식으로 보안을 해결하는지 공부 해봐야 겠다.. 라는 생각을 했습니다. 

 


그렇다면, 먼저 대체 웹 취약점 및 보안에 대해 먼저 알아보겠습니다.

웹 취약점과 보안?

  • 웹 애플리케이션은 퍼블릭 클라우드에서 Secret key / Access key 만큼이나 공격 포인트가 되는 부분입니다. 
  • SQL injection , XSS , Local file injection 
  • 어플리케이션 생산 주기의 변화에 따라 보안 역시 자동화된 보호가 필요하단 것을 느끼게 됨
  • WAF와 같은 보안 솔루션 등장

안렙에 따르면 2019년도 사이버 공격 통계중에서 웹 기반 공격과 어플리케이션 취약점 공격이 70% 이상의 해킹 공격의 높은 비중을 차지한다고 발표했습니다.

그중에서도 SQL injection , XSS , Local file injection 공격이 95%를 차지했다고 발표했습니다.

 

제가 위에서 초보 개발자일때 경험을 토대로 작성한 블로그 포스팅에는 실제로 프로그래밍을 통한 공격에 대한 대처들이 포함되어 있는데요, 위에서도 말했듯이 지엽적인 코드 변경을 통해 보안성 심의를 대처하는것은 올바른 방법은 아니라고 알고 있습니다. 

 

점차 어플리케이션의 생산주기가 짧아지고 점점 더 빠른 속도로 개발되어 가는 현재 Cloud Native 상황에서, 보안 역시 자동화된 보호가 필요하단 것을 느끼게 되었습니다. 그래서 나온것이 WAF ( 웹 방화벽 ) 입니다.

WAF가 웹 시장에서 주목받기 전에 웹 보안은 개발자의 보안 프로그래밍 능력에 의존되었습니다. 이는 종종 다양한 문제점을 일으켰고, 침해사고로 이어졌습니다. 

 

 

 웹 어플리케이션 방화벽 ( WAF ? )

  • 웹 애플리케이션 방화벽(WAF)은 웹의 비정상 트래픽을 탐지하고 차단하기 위한 방화벽입니다. 
  •  웹 방화벽은 웹 프로토콜 HTTP 정보를 바탕으로 차단 룰을 설정
  • 사람은 누구나 실수하기 때문에 수많은 테스트와 충분한 검토 후 서비스를 출시하더라도 보안 문제는 발생하곤 함
  • WAF 는 이러한 웹 보안 문제나 실수를 보완하기 위한 방파제 역할
  • 서비스는 정기적으로 개편되거나 변화하면서 새로운 기능이 생기거나 사라집니다. 그때 마다 새로운 취약점이 나타날 수 있습니다.
  • 많은 비용과 보안 프로그래밍에 대한 지식, 충분한 코드 리뷰, 취약점 진단, 모의 침투 테스트 등 많은 팀과 인력의 노력이 요구
  • 보안 자동화 필요

 

✅ 웹 취약점 및 보안 실습

✔️ AWS WAF 에 대해 학습하기 전에 DBWA 어플리케이션을 통해 웹 취약점 공격에 대한 실습을 먼저 진행

✔️ AWS WAF Configuration A to Z Workshop 내용 참고 ← 기본 ALB도메인(옵션:개인 도메인) 접속해서 공격 실습 - 링크

 

 

1️⃣ 실습환경 만들기  ( 사전준비 )

 

KEYNAME=kp-koo
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/security/ahss-waf.yaml

# CloudFormation 스택 배포
aws cloudformation deploy --template-file ahss-waf.yaml --stack-name mywaf --parameter-overrides KeyName=$KEYNAME --region ap-northeast-2 --capabilities CAPABILITY_NAMED_IAM

# CloudFormation 스택 배포 완료 후 EC2 2대 IP 출력
aws cloudformation describe-stacks --stack-name mywaf --query 'Stacks[*].Outputs[*].OutputValue' --output text
 
# 각각 EC2 SSH 접속 : 아래 키파일 경로는 자신의 환경에 맞게 변경하자!
13.125.243.12   3.36.111.129


ssh -i kp-koo.cer ec2-user@13.125.243.12
ssh -i kp-koo.cer ec2-user@3.36.111.129

 

2️⃣ 실습환경 확인 (DBWA )

# mariadb 확인 : 계정(root / qwe123)
mysql -V
systemctl status mariadb
mysql -u root -pqwe123 -e "SHOW DATABASES;"

# apache web 확인 & DVWA 웹 디렉터리 확인
httpd -v
systemctl status httpd
tree /var/www/html/ -L 1
tree /var/www/html/ -L 2

# DVWA의 연결 DB 정보 확인
grep 'db_' /var/www/html/config/config.inc.php

# php 정보 확인
php -v
php --ini

# EC2 Instance Profile 확인 : AmazonS3ReadOnlyAccess
aws s3 ls
curl -s http://169.254.169.254/latest/meta-data/ ; echo
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRole | jq

# 웹 접속 로그 실시간 확인
tail -f /var/log/httpd/access_log
tail -f /var/log/httpd/access_log | grep -v ELB-HealthChecker

## 로그 확인
접속자 IP 주소 - - 접속 시간 - 요청 방식 - 요청 페이지 - 프로토콜 버전 - HTTP 응답 코드 - 전송 크기 - 접속 브라우저 도구
10.0.1.120 - - [10/Sep/2023:14:28:59 +0900] "GET /favicon.ico HTTP/1.1" 304 - "http://waf.gasida.link/1.html" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"

 

2️⃣ 실습환경 확인 (Attacker)

  • hydra 
  • docker-compose / docker
#
hydra
docker info
docker-compose version

 

2️⃣ 실습환경 확인 (ALB )

  • DBWA 웹에 접근시 ALB의 도메인 주소로 접근 (My-ALB-1729801927.ap-northeast-2.elb.amazonaws.com)

DNS 이름 복사 후 접근

 

3️⃣ route53 레코드 등록

1 alb.taskoo.net A 단순 - dualstack.my-alb-1729801927

 

 

4️⃣ 데이터 베이스 Reset 후 접속 

여기까지 사전 준비가 끝났다. 우리는 Apache와 Mysql DB를 통한 웹사이트를 만들었고, 이 웹사이트를 통해 
해커들이 어떤식으로 공격을 할수 있는지에 대해 확인 해볼 심산이다.

 


 

 

 

 

첫번째 , 개발자 도구를 통한 웹 노출 정보

 

 

  • 아파치 버전 - 해당 버전으로 CVE 취약점 패치 검색 후 공격 타겟이 될수 있음
  • PHP 버전 -  해당 버전으로 CVE 취약점 패치 검색 후 공격 타겟이 될수 있음

 

 

🆘 대응방법 : apache2.conf에 서버 정보 노출 최소화 , 비활성화 설정 

# apache2.conf 파일 수정
ServerTokens Prod   # 웹 서버 정보 노출 설정 최소화
ServerSignature Off # 웹 브라우저에 정보 노출 비활성화
...
systemctl restat httpd

 

 

 

 

번째 , SQL injection 공격 

 

 

  • SQL injection은 로그인 창과 같은 입력 파라미터를 받는 곳에 or 연산자를 통해 한쪽 조건을 TRUE로 만들어서 조건문을 무효화 하여 원하는 정보를 데이터베이스에서 조회 또는 조작 하는 공격이다.
  • 아래와 같이 입력값을 넣을 경우 데이터베이스에 전체 테이블을 조회해서 노출시킨다.
# 입력값에 다음과 같이 입력합니다.
' OR 1=1 #

✔️ [DVWA EC2] 에 접속하여 데이터 베이스 확인도 해봅니다.

# ec2 접속 후 

mysql -uroot -pqwe123
---------------------
SHOW DATABASES;
USE dvwa;
SHOW TABLES;
SELECT * FROM users;
SELECT first_name,last_name FROM users;
SELECT first_name,last_name FROM users WHERE user_id='1';
SELECT first_name,last_name FROM users WHERE user_id='attacker' or 1=1;
SELECT * FROM users WHERE user_id='attacker' or 1=1;
exit
---------------------

✔️ [DVWA EC2] 이렇게 우회하는것도 가능합니다.

# 예를 들어 아래 처럼 정상 로그인(ID/PW) 입력에서
SELECT user_id FROM user_table WHERE user_id='john' AND password='qwe123'

# 아래처럼 입력 시 
SELECT user_id FROM user_table WHERE user_id='attacker' or 1=1-- AND password='test'
## 결과적으로 아래처럼 변조되어 password에 어떤 값을 입력하든 로그인 허용됨
SELECT user_id FROM user_table WHERE user_id='attacker' or 1=1

 

 

🆘 대응 방법 :  입력 값을 ArrayList로 받아서 SQL injection 공격을 차단함 -> 해당 DBWA 어플리케이션에서는 ArrayList로 입력값에 

이상한 값을 넣을수 없게 유효성 검사를 해야 한다를 의미하는 것이지, 반드시 ArrayList로 해야되는것은 아닙니다. 

 

 

 

 

 

 

 번째 , Reflected XSS 공격 

 

 

✔️ [DVWA 웹 ] 입력 창에 다음과 같은 스크립트를 입력 한 후 Submit 전송

<script>alert(document.cookie)</script>

✔️  노출된 쿠키 

✔️ PHP 세션 ID값 확인 : [Attacker] EC2 접속 후 curl -> PHPSESSID

#
curl -s 10.0.0.10/vulnerabilities/weak_id/ -v
...
< Set-Cookie: PHPSESSID=nr4sfscvamrrarg8vpc5vq51u1; 어쩌구 >
...

[root@Attacker ~]# curl -s 10.0.0.10/vulnerabilities/weak_id/ -v
* processing: 10.0.0.10/vulnerabilities/weak_id/
*   Trying 10.0.0.10:80...
* Connected to 10.0.0.10 (10.0.0.10) port 80
> GET /vulnerabilities/weak_id/ HTTP/1.1
> Host: 10.0.0.10
> User-Agent: curl/8.2.1
> Accept: */*
> 
< HTTP/1.1 302 Found
< Date: Wed, 13 Sep 2023 02:01:28 GMT
< Server: Apache/2.4.57 () PHP/8.2.9
< Upgrade: h2,h2c
< Connection: Upgrade
< X-Powered-By: PHP/8.2.9
< Set-Cookie: security=impossible; path=/; HttpOnly
< Set-Cookie: PHPSESSID=nr4sfscvamrrarg8vpc5vq51u1; expires=Thu, 14 Sep 2023 02:01:28 GMT; Max-Age=86400; path=/; HttpOnly; SameSite=1
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate
< Pragma: no-cache
< Location: ../../login.php
< Content-Length: 0
< Content-Type: text/html; charset=UTF-8
< 
* Connection #0 to host 10.0.0.10 left intact

 

 

🆘 대응 방법 : script  태그 유효성 검사 제거 

# 이런 식으로 <script>라는 부분을 유효성 검사 해버립니다.

$name = str_replace( '<script>', '', $_GET[ 'name' ] );

 

 

 

 

 

 번째 , Stored XSS 공격 

 

 

  • Stored XSS 공격은 XSS 공격 방법 중 하나로 공격자가 공격 Script 를 웹사이트에 저장해두거나 게시판 등의 게시글 등에 저장해둔 후 사용자가 해당 페이지에 접속하거나 게시글을 클릭하였을 경우 실행되도록 하는 공격
  • Reflected XSS와의 공격 방법은 비슷하지만 약간의 차이점
  • Stored XSS는 데이터베이스에 스크립트가 저장되고 Reflected XSS는 응답 페이지로 바로 클라이언트에 전달된다

 

<script>alert(document.cookie)</script>

✔️ Name 부분에는 admin을 입력하고 Message 부분에는 위의 XSS 스크립트 코드를 입력한 후 Sign Guestbook 클릭! 

 

 

🆘 대응 방법 :  script  태그 유효성 검사 제거 

# Medium Reflected XSS Source
<?php

header ("X-XSS-Protection: 0");

// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    $name = str_replace( '<script>', '', $_GET[ 'name' ] );

    // Feedback for end user
    echo "<pre>Hello {$name}</pre>";
}

?>

 

 

 

 

 

 

 다섯번째 , Command Injection 공격 

 

  • Command Injection 공격 은 이름 그대로 사용자의 요청에 명령어를 삽입 하여 실행하는 공격을 말합니다.
  • 실습 페이지는 IP에 ping을 테스트 하는 페이지입니다. 
  • 공격 의도가 있는 사용자가 ping 테스트 입력창에 IP와 && 명령어를 통해 다른 정보를 가져가는 부분을 확인할수 있습니다.
1.1.1.1 && cat /etc/passwd

 

 

🆘 대응 방법 : &&와 ; 는 제거 


if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    $target = $_REQUEST[ 'ip' ];

    // Set blacklist
    $substitutions = array(
        '&&' => '',
        ';'  => '',
    );