도커 네트워크 생성
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로 사용하는 것이다.