카테고리 없음

SW 개발보안 10일차 - 필터링

ajh 2026. 5. 21. 17:43

도커 네트워크 생성

docker net cr \
> --subnet (주소) \
> --gateway (주소) \
> (네트워크 이름)

 

컨테이너, 이미지 설치 

docker run -d --res al \

> --network \

> --hostname \
> --name \
> -p \
> -v /~/~/~:/~/~ \
> images

 

설치한 컨테이너 이미지로 추출 후 .tar파일로 저장 

docker comm (원본 컨테이너) (저장할 이미지)

이미지를 tar 파일로 저장한다.
docker sa -o (저장할 이미지.tar) (저장할 이미지)

 

기존 컨테이너, 이미지 삭제 
docker rm -f (컨테이너)
docker rmi (이미지)

docker save로 만든 파일을 docker load 명령어로 올린다. 
-i 옵션은 input을 의미한다.
docker load -i (저장한 이미지.tar)

 


칼리 리눅스 ssh 연동 설정 

root@kali:~# systemctl enable --now ssh.service 

 

*****************PHP 배열**********************

배열
참고: https://www.php.net/manual/en/book.array.php

배열은 여러 개의 값을 하나의 변수에 저장한다.

형식: $배열명[인덱스]
PHP에서는 C언어와 다르게 인덱스로 숫자와 문자열을 같이 사용한다.

배열 요소의 추가
$array[0] = 1;
$array[1] = 2;
$array[2] = 3;

$array
+-----+-----+-----+
|  1  |  2  |  3  |
+-----+-----+-----+
  [0]   [1]   [2]

 

연관 배열
  . 배열의 인덱스(방번호)를 숫자 인덱스가 아니라 이름이 있는 인덱스(key)로 저장하는 배열이다.
  . 연관 배열로 저장한 배열은 값을 꺼낼 때 $array[0], $array[1], $array[2] 같은 번호로 사용하면 에러이다.
    $array['name'], $array['ip'], $array['age'] 와 같이 문자열(key)를 사용해야 한다.

$student
+---------+------+---------+
|  MrHong |  20  |  12.25  |  <-- array_values(): key, value 둘중에 value 를 출력하는 함수
+---------+------+---------+
|         |      |
|         |      +-- $student['birthday']
|         +-- $student['age']
+-- $student['name']  <-- array_keys(): key, value 둘중에 key 를 출력하는 함수

형식: 변수명 = array('key' => 'value' | value ...);
$student['name'] = "MrHong";  // 연관 배열
$student['age'] = 20;
$student['birthday'] = "12.25";

 

 

foreach문

  . 연관 배열을 출력하기 위한 문법
    - foreach 문은 배열의 요소를 처음부터 끝까지 하나씩 꺼내서 반복 처리할 때 사용하는 제어구조이다.
    - 연관 배열의 키(key)와 값(value)을 함께 출력할 때 매우 자주 사용한다.

    - foreach문 형식:
      foreach(배열변수명 as <키저장변수명> => <값저장변수명>)      {
          실행문
      }
    의미 설명
    - 배열변수명 : 반복할 배열
    - 키저장변수명 : 배열의 키가 저장될 변수
    - 값저장변수명 : 배열의 값이 저장될 변수
    - 배열의 키와 값을 하나씩 꺼내서 실행문을 반복 수행한다.

*****************PHP 배열**********************

 

DVWA Command Injection 공격

medium 설정시 입력값의 일부를 검증한다 

 // Set blacklist
        $substitutions = array(    <= 필터링
                '&&' => '',
                ';'  => '',
        );

 

// Remove any of the charactars in the array (blacklist).
$target = str_replace( array_keys( $substitutions ), $substitutions, $target );  <= 검증 

 

PHP str_replace() 함수
  . 문자열에서 특정 문자열을 찾아 다른 문자열로 바꾸는 함수
  . 사용 형식
    str_replace(찾을문자열, 바꿀문자열, 대상문자열);

<?php
// str_replace2.php
// 문자열 치환 (변수 2개 이상)

$cmd = "127.0.0.1 && cat /etc/passwd ; id";

$blacklist = array("&&", ";");
$result = str_replace($blacklist, "" ,$cmd);  // str_replace(2,3,1);

echo "원본: " . $cmd . "<br>\n";
echo "필터링 후: " . $result;
?>

 

$blacklist 배열에 포함된 모든 요소(&&, ;)를 찾아 각각 빈 문자열("")로 치환한다

 

http://192.168.100.25:81/php/str_replace2.php
원본: 127.0.0.1 && cat /etc/passwd ; id
필터링 후: 127.0.0.1 cat /etc/passwd id

소스보기
원본: 127.0.0.1 && cat /etc/passwd ; id<br>
필터링 후: 127.0.0.1  cat /etc/passwd  id

<?php
// str_replace3.php
// 문자열 치환 (변수 2개 이상)

$target = "127.0.0.1 && cat /etc/passwd ; id";
echo "원본: " . $target . "<br>\n";

$substitutions = array("&&" => '', ";" => '');
$target = str_replace(
    array_keys( $substitutions ),
    $substitutions,
    $target
);

echo "필터링 후: " . $target;
?>

 

array_keys($substitutions)를 통해 찾을 대상인 array("&&", ";") 배열을 먼저 생성한다

이 배열은 키(Key) => 값(Value)값의 형태를 가지게 된다 

 

str_replace 함수는 원래 str_replace(찾을문자, 바꿀문자, 원본문자) 구조를 가진다. 하지만 여기에 배열이 들어가면 

array_keys($substitutions) : $substitutions 배열에서 Key만 뽑아내어 새로운 배열을 만든다.
결과적으로 array("&&", ";")가 되어 str_replace2.php에서 썼던 블랙리스트 배열($blacklist = array("&&", ";");)과

똑같은 모양이 된다. 

 

$substitutions : 2번째 인자인 '바꿀 문자' 자리에 연상 배열 자체를 통째로 넣었습니다.
PHP의 str_replace 함수는 1번째 인자와 2번째 인자가 둘 다 배열일 때, 1번째 배열을 Key, 2번째 배열을 Value로 1:1로 매칭시켜 치환한다. 즉, array에서 설정한대로 ("&&" => '', ";" => '') 치환시킨다.

 

만약 보안 정책이 바뀌어서 &&는 [AND]로 바꾸고, ;는 [SEMICOLON]으로 다르게 치환해야 한다면 array 배열에서

필터링할 변수만 바꿔주면 된다

 

http://192.168.100.25:81/php/str_replace3.php
원본: 127.0.0.1 && cat /etc/passwd ; id
필터링 후: 127.0.0.1 cat /etc/passwd id

소스보기
원본: 127.0.0.1 && cat /etc/passwd ; id<br>
필터링 후: 127.0.0.1  cat /etc/passwd  id

항목 str_replace2.php str_replace3.php
배열 형태 인덱스 배열 (값만 존재) 연관 배열 (Key => Value 쌍)
배열 구조 array("&&", ";") array("&&" => '', ";" => '')
치환 규칙 지정 두 번째 인자("")로 공통 적용 Key를 찾아 Value로 각각 매칭하여 치환
str_replace 형태 str_replace($blacklist, "", $cmd) str_replace(array_keys($sub), $sub, $target)

 

즉 medium 설정시 입력값을 필터링해서 기존의 &&, ; 를 통한 인젝션 공격을 막는다

하지만  파이프(|), or(||) 를 통해 필터링을 우회할 수 있다

 

파이프(|): 이전 명령어의 출력값을 다음 명령어의 입력값으로 넣어서 실행하기에

ip, pwd등 입력을 받지 않는 명령어들을 실행 가능하다 

 

or(||): 앞의 명령어가 실패하면, 뒤의 명령어를 실행하라는 논리 연산자라 앞의 명령어를 오류가 나는 값으로 입력 후 

뒤의 명령어를 입력을 하면 필터링을 우회할 수 있다.


mywebsite 필터링하기

 

http://192.168.100.10/index.html

 

admin 로그인 정보: admin/111111 
아이디: ' or 1=1#
비밀번호: 1

 

단순 (') 필터링 
[root@victim ~]# cd /var/www/html/

[root@victim html]# vi loginok.php

...

 32 $userid = $_POST['userid'];
 33 $userpw = $_POST['userpw'];
 34
 35 // 필터링
 36 $userid = str_replace(" ' ", ' ', $userid);  <= (')를 필터링해서 인젝션 공격이 들어와도 나머지 코드를 에러로 만든다 
 37
 38 // POST 방식으로 넘어온 userid/userpass 를 DB에서 비교한다.

 

블랙리스트 기반 필터링

  . 입력값에서 위험하다고 판단한 문자나 단어를 미리 정해두고 제거하거나 차단하는 방식이다.


블랙리스트 기반 필터링 함수 라이브러리 

<?php
/*
 * 파일명: security_lib.php
 * 프로그램 설명: 보안 라이브러리 함수
 */

// 블랙 리스트 기반 필터링
function blacklist_filter($input) {
    $blacklist = array(
        "'"         => "",
        '"'         => "",
        "#"         => "",
        "--"        => "",
        ";"         => "",
        "\\"        => "",
        "union"     => "",
        "select"    => "",
        "from"      => "",
        "version"   => "",
        "database"  => "",
        "user"      => "",
		"("         => "",
        ")"         => "",
        ","         => ""
        );
    return str_replace(array_keys($blacklist), $blacklist, $input);
}
?>

 

==================== loginok.php ====================
... ...
/***** Security Check *****/
require_once("./security_lib.php");
/***** Security Check *****/

$userid = $_POST['userid'];
$userpw = $_POST['userpw'];

$userid = blacklist_filter($userid);
$userpw = blacklist_filter($userpw);
... ...

 

블랙리스트 설정 

$blacklist = array("'" => "", '"' => "", "#" => "", "--" => "", ";" => "", "\\" => "" );

array_keys($blacklist)는 블랙리스트에서 특수문자들만 쏙 뽑아냄

return str_replace(array_keys($blacklist), $blacklist, $input);

 

함수 실행 순서 

1. 치환 시작: str_replace가 $input 문자열을 처음부터 끝까지 스캔한다

2. 첫 번째 발견: admin 뒤에 있는 작은따옴표(')를 발견하면 블랙리스트에 매칭되므로 이를 빈 문자("")로 바꾸어 삭제한다.

결과: admin --

3. 두 번째 발견: 이어서 뒤에 있는 하이픈 두 개(--)를 발견하면 이 역시 빈 문자("")로 바꾸어 삭제한다. -> 결과: admin 

4. return: 특수문자가 싹 제거되고 남은 admin 문자열만 최종적으로 반환된다.

 

함수 호출

앞서 정의한 security_lib.php 파일을 이 파일 안으로 불러옴

require_once("./security_lib.php"); 

 

사용자가 로그인 폼에 입력하고 전송한 아이디($_POST['userid'])와 비밀번호($_POST['userpw'])를 각각 $userid와 $userpw 변수에 담음

$userid = $_POST['userid'];
$userpw = $_POST['userpw'];

 

사용자가 입력한 아이디와 비밀번호를 위에서 만든 blacklist_filter() 함수에 집어넣음
만약 해커가 아이디에 admin' -- 같은 공격 코드를 넣었다면, 이 함수를 거치면서 특수문자가 삭제되어 $userid에는 오직 admin 만 남는다
특수문자가 제거된 안전한 문자열을 다시 $userid와 $userpw 변수에 덮어쓴다

$userid = blacklist_filter($userid);
$userpw = blacklist_filter($userpw);


UNION sql 인젝션

 

필터링을 하지 않은 경우

http://192.168.100.10/?id=bbs1+union+select+1,2,3,4,5,6,7,8&m=list
http://192.168.100.10/?id=bbs1+union+select+1,version(),3,database(),5,6,7,8&m=list


==================== list.html ====================
... ...
8 if(!defined('webpage')) exit; // 직접 접근 금지
9
10 /***** Security Check *****/
11 include_once("security_lib.php");
12 $id = blacklist_filter($_GET['id']);
13 echo $id;
14 //exit;
15 /***** Security Check *****/
16
17 include "dbconnect.php";
... ...
 55         <td> <a href=?id=<?=$id?>&m=read&no=<?=$row['no']?>> <?=$row['title']?></a>
... ...
 75     <tr bgcolor=#ffffff>
 76         <?php $id = $_GET['id']?> <= 삭제한다 
 77         <td align=center colspan=4> <a href="/?id=<?=$id?>&m=write">글쓰기</a>
==================== dbconnect.php ==================== 
... ...  

8 $DBHOST = "localhost";

9 $DBUSER = "root";
10 $DBPASS = "1234";
11 $DBNAME = "mywebsite";
12 //$TBNAME = (isset($_GET['id'])) ? $_GET['id'] : "";
13 $TBNAME = (isset($id)) ? $id : "";
14 $connect = @mysqli_connect($DBHOST, $DBUSER, $DBPASS, $DBNAME) or die("DBMS 접속 실패!!!");
15 ?>

... ...

 

$_GET['id'] 를 $id = blacklist_filter($_GET['id']); 필터링해서 
필터링한 이후에는 $_GET['id'] 는 사용하면 안되고 $id로 사용하는 것이다.