Session

세션 데이터는 세션 데이터 저장소에 보관된다.

SID라는 고유 식별자로 세션 데이터 저장소에서 특정 레코드를 식별한다.

세션 저장소 경로는 php.ini의 ``session.save_path``에 지정되며 ``php session_save_path()``로 얻거나 설정할 수 있다.

이를 이용해 세션 저장소에 직접 접근해서 다른 세션 데이터를 얻어올 수 있다.

```php

$path = ini_get('session.save_path');

$handle = dir($path);


while ($filename = $handle->read()) {

    if (substr($filename, 0, 5) == 'sess_') {

        $data = file_get_contents("$path/$filename");

        if (!empty($data)) {

            session_decode($data);

            $session = $_SESSION;

            $_SESSION = array();

            echo "Session [" . substr($filename, 5) . "]\n";

            print_r($session);

            echo "\n--\n\n";

        }

    }

}

```


PHP의 PHPSESSID 처리

  1. ``php session_start()``를 호출하면 PHP는 현재 요청의 cookie || query string에 `` PHPSESSID``가 있는지 확인한다.
  2. SID가 있는 경우 : 저장소에서 해당 세션의 데이터를 읽어들이고 ``php $_SESSION``에 저장한다.
    SID가 없는 경우 : SID를 생성하고 세션 데이터 저장소에 새로운 레코드를 생성한다. 
  3. 쿠키를 설정하고 헤더를 캐싱한다.


HTTP Session hijacking ( L7 )

HTTP 자체는 stateless protocol이라, SID를 이용해 세션을 식별하고, SID는 결국 쿠키이므로, 쿠키를 훔쳐내면 다른 사용자의 세션을 가져올 수 있다.


유효한 SID를 얻어내기 위한 방법으로는 세 가지가 있다.

  1. 예측
  2. 캡쳐
  3. 고정

예측

보통 SID는 충분히 랜덤하게 생성되기 때문에 이 방법으로는 어렵다.


캡쳐

monitor 모드로 패킷 스니핑해서 가져오는 방법을 사용할 수 있다.



고정

PHP는 요청에 포함된 SID가 있으면 새로운 SID를 생성하지 않고 그 SID에 연결된 세션 저장소를 사용한다.

이를 이용해 victim이 공격자가 미리 지정해 놓은 SID를 사용하도록 하는 방법이다.

```html

<a href="http://example.org/index.php?PHPSESSID=1234">example.org</a>

```


query string에 `` PHPSESSID``를 지정하고 redirect시키는 방법도 있다.

```html

<meta http-equiv="refresh" content="0; 

url=http://example.org/index.php?PHPSESSID=1234" />

```

```js

<script>location.href='http://example.org/index.php?PHPSESSID=1234'</script>

```


이렇게 해서 만들어진 세션 데이터 저장소 레코드는 `` PHPSESSID=1234``를 지정하면 접근할 수 있어 공격자가 세션 데이터를 얻어낼 수 있다.


세션 고정 공격을 예방하기 위해서는 SID를 발급할 때 flag를 설정해두고, SID를 전송받았을 때 flag가 설정되어 있는지를 체크해 실제로 발급한 SID인지를 확인하는 방법이 있다.

```php

if (!isset($_SESSION['initiated'])){

    session_regenerate_id();

$_SESSION['initiated'] = TRUE;

}

```

그러나 이 방법은 공격자가 해당 사이트를 방문해서 SID를 받은 다음, 이 SID를 고정 공격에 사용하면 해당 사이트에서 정상적으로 발급받은 SID가 맞기는 하니까 우회할 수 있다.


그래서 다른 방법을 사용해야 한다. 생각해보면 세션 고정 공격은 공격자가 정상적으로 얻을 수 있는 권한보다 높은 권한을 가진 SID를 획득하기 위해 수행하는 공격이므로, 로그인 하는 등 권한이 변경될 때 마다 SID를 재생성한다면 무력화할 수 있다.

```php

$_SESSION['logged_in'] = FALSE;

if (check_login()){

    session_regenerate_id();

$_SESSION['logged_in'] = TRUE;

}

```

단, 모든 페이지에서 SID를 재생성하는 것은 비효율적이며 그렇게 한다고 더 안전한 것도 아니다.


Note ) 뒤로가기 했는데 갑자기 로그인이 풀린다던가 하는 것은 SID가 변경되었고, 뒤로가기 하면서 변경되기 전의 SID를 가리키게 돼서 그렇다.


is_hijacked?

`` User-Agent``의 일관성을 검사하는 건 별로지만, 심층 방어의 관점에서 보면 안하는 것 보다는 낫다.

```php

if (isset($_SESSION['HTTP_USER_AGENT']){

    if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])){

    // password authentication or exit

    }

} else {

    $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);

}

```

그러나 일반적으로 SID는 쿠키에 넣어서 전송되기 때문에 SID를 알고 있다면 모든 HTTP header 정보를 알고 있을 가능성이 높고, 이 경우 `` User-Agent``를 비롯한 모든 값을 복사해 사용할 수 있다.


따라서 검사에 사용하는 정보들을 salt와 함께 해싱한 다음 이를 토큰으로 사용해서 페이지의 모든 내부 링크가 query string에 토큰을 포함하도록 구성하는 방법으로 보완할 수 있다. 

```php

<?php

$url['token'] = rawurlencode($token);

$html['token'] = htmlentities($url['token'], ENT_QUOTES, 'UTF-8');

?>


<form action="index.php?token=<?= $html['token'];?>">

...

```


세션 하이재킹을 막기 위해서는 

  1. SID를 비공개하거나
  2. 세션이 hijacking되었는지를 식별할 수 있는 방법을 사용하거나
둘 중 한 가지를 만족해야 한다.


1. 

SID 비공개는 SSL로 처리하면 된다. 근데 암복호화를 사용하는건 어쨌든 오버헤드를 동반하는 일이기도 하고, 하나의 페이지라도 HTTP로 처리한다면 거기서 SID가 노출되니까 모든 페이지를 SSL로 처리해야만 한다. 대체로 이 방법을 사용한다. 구글이나 페이스북이나...

그러나 SSL을 이용하는 경우에도 `` ClientHello``에 이전 SID를 적어 보내면 이전 세션 연결이 재개되기 때문에
이를 이용해 hijacking 할 수 있다. 고 하는데 직접 해보지는 않았다.


2.

src IP를 사용해 검증하는 방법이 괜찮기는 한데, 이건 각 웹사이트들이 IP보안이라는 항목으로 제공하고 있는 듯. 그리고 모바일에서는 이동하면서 IP가 변경되거나 와이파이를 잡는 경우 매번 다시 로그인해야 하기 때문에 유저가 불편함.

물론 IP도 spoof 할 수 있지만, 서로 다른 원거리 서브넷에 위치한 victim으로 IP spoof한다면 라우팅이 제대로 되지 않아 response가 돌아오지 않을 듯. ( 실험해보지는 않았다. )

PHP 단에서 L3 real IP addr을 확인하는 방법은 ``php $_SERVER['REMOTE_ADDR']``를 사용하는 것.




'Security > WebHacking' 카테고리의 다른 글

Blind SQL Injection  (0) 2017.08.08
Basic SQL injection  (0) 2017.08.08
인증(Authentication)과 인가(Authorization)  (0) 2017.06.28
Brute Force / Replay Attack  (0) 2017.06.28
Filtering / Escape  (0) 2017.06.27