Plit00's Story

Prepare() : WordPress Exploit 본문

잡동사니/webhacking

Prepare() : WordPress Exploit

plit00 2019. 8. 15. 23:18

[7월15~22일]

 prepare() 함수를 이용하여 wordpress 익스하는 밑의 영상을 토대로 공부한것을 작성합니다. 

[취약점 영상 :: https://www.youtube.com/watch?v=h17hOpaJ0XE]

WordPress

오픈소스 콘텐츠 관리 시스템이며 PHP 개발하였기때문에 취약점이 많습니다.

 

 

Wordpress Core

WP는 좋은 플러그인으로 사용자화를 하고 확장을 합니다.

하지만, 이 플러그인마저도 버그바운티 프로그램에서 치명적인 버그가 발생되어 top에 올라가곤합니다.

 버그를 통해서 WP에서 개발자들의 실수를 찾아보는것이 우리가 할 일입니다.

(이것은 모든 버그바운티를 할때 공통적인 부분입니다. 해커는 개발자의 실수를 이용하는 것입니다.)

 

 

PDO(PHP Date Object)

-DB에 접근하는 공통 API를 사용자에게 제공하는 목적으로 만들어졌습니다.

  • prepare()
    실행할 문자을 입력하고 문장 객체를 반환합니다.
  • bind()
    특정 bind 객체와 class 범위에 closure을 복제합니다.
  • execute()
    input parameter을 실행합니다.
prepare()
=>public PDO::prepare ( string $statement [, array $driver_options = array() ] ) : PDOStatement

bind()
=>public static Closure::bind ( Closure $closure , object $newthis [, mixed $newscope = "static" ] ) : Closure

execute()
=>public PDOStatement::execute ([ array $input_parameters ] ) : bool

즉, 여러가지 DB 객체지향적으로 제어하는 방법을 표준화 시킨것입니다.

 

Prepare() Function

PDO :: prepare ( string $statement [, array $driver_options = array() ] ) 

string $statement php단에서 서버와 통신을 할때의 함수 메소드를 통해 실행될 sql 문을 준비하게되는 구문입니다.
execute() prepare() 이용해서 말이죠

이것을 이용하여 호출하게 된다면 매개 변수를 수동으로 인용하고 이스케이프 필요가 없이 sql 공격을 방지하는데 도움이되는 함수입니다.

<?php
  
$std = $dbh->prepare(‘SELECT name, color, calories FROM fruit WHERE calories < color AND color’);
  
$std->execute(array(150, ‘blue’));
  
$blue = $sth->fetchAll();
  
$sth->execute(array(200, ‘black’));
$black = $sth->fetchAll();

?>

 

PDO Prepare() Statements

  • Legacy Code
    테스트가 불가능하거나 어려운 코드를 의미합니다.
    PDO 설정상 레거시코드를 테스트할 수 없습니다.
    그 이유는 WP의 기존 플러그인과의 호환성에 문제가 있기때문입니다. 

  • PDO & PHP
//prepare()은 해킹하는 시도를 하는 사용자의 입력을 삭제하고 sql의 자리표시에 ' 를 포함시킵니다.

$query = $wpdb ->prepare( “SELECT * FROM table WHERE column1 = %s”, $_GET[‘c1’] );
$wpdb -> query( $query );

//예를 들어 유저가 이러한 입력을 했다고 봅시다.
prepare() sanitizes
User input : 1’OR’1’=1’

//' 포함
SELECT * FROM table WHERE column1 = ‘1\ ‘OR\ ‘1\ ‘=\ ‘1’

 

Double Prepare

4.8.3 이전의 WordPress는이 매우 일반적으로 사용되는 코드에있는 SQL 삽입에 취약했습니다.

4.7.4 버전같은경우는 이것을 이용하여 double prepare sql injection 사용하였습니다

$query = $wpdb ->prepare( “SELECT * FROM table WHERE column1 = %s”, $_GET[‘c1’] );
$query = $wpdb ->prepare( $query . “column1 = %s”, $_GET[‘c2’] );
$wpdb -> query( $query );

 

첫번째 구문의 $_GET에서 값을 c1으로 넣어줬습니다. 그리고 2번째의 구문에서는 c2 넣었죠.

이것을 실행하게된다면 script.php c1=변수 c2 쿼리가 들어가게되면서 오류가 발생하게됩니다.

script.php?c1= %s&c2[]OR 1=1 - - x&c2[]=abc

 

2가지의 구문이 있습니다.
첫번째는 위와같이 변수값을 컬럼1 배당하고 2값에도 지정해줍니다. 이런다면 위와값이 스크립트는 컬럼1 동일하게 할당되는것이죠
두번째는 sql구문에서 한것과같이 or 1=1 - - x 넣어줬습니다. 

근데 아까와 말했듯이 자리 표시에 싱글쿼터를 강제로 하나 넣어주게되면서 취약점이 생기게되는것이죠 

Prepare() 1 :: SELECT *FROM table WHERE column1 = ‘ %s ’ AND column2 =%s
Prepare() 2 :: SELECT *FROM table WHERE column1 = ‘ ‘ OR 1=1 - - x’ ‘ AND column2 = ‘abc’;

 

1

function prepare($query, $args)
 {
 	if(is_array($args[0])) $args = $args[0];
 	$query = preg_replace('/%s/', "'%s'", $query);
 	arrya_walk($args, array(%this, 'esc_sql'));
 	$query = vsprintf($query, $args);
 	return str_replace('%', $this->placeholder_escape(), $query);
 }
 function query($query)
 {
 	$query=str_replace($this->placeholder_escape(), '%', $query);
 }

Sql 삽입을 완화하기 위해 WP는 prepare()에 대한 수정을 발표했습니다.

이 수정내용은 모든 자리에 표시자를 대체합니다.
prepare()에 오기전 모든 자리를 66개의 문자열을 사용자 입력받게했습니다.

 

표시자리수에 '가 강제적으로 포함되어 취약점이 발생되었는데 이것을 막기 위함인거 같습니다.

placeholder_escape == prepare ()에 의해 반환 된 쿼리에 사용할 자리 표시 자 이스케이프 문자열을 생성하고 반환

 

$query = $wpdb ->prepare( “SELECT * FROM table WHERE column1 = %s”, $_GET[‘c1’] );
\
$query = $wpdb ->prepare( $query . “column1 = %s”, $_GET[‘c2’] );
$wpdb -> query( $query );

User input : script.php?c1= %s & c2[]=abc

prepare() 1: SELECT * FROM table WHERE column1 = ‘ {13f..0d23}s ‘
prepare() 2: SELECT * FROM table WHERE column1 = ‘ {13f..0d23}s ‘ AND column2 = ‘abc’;
Query():     SELECT * FROM table WHERE column1 = ‘ %s ‘ AND column2 = ‘abc’;  

 모든  % 효과적으로 고유한 66개의 문자열 대체됩니다

 

Attack

1. $query_results = new WP_Query (‘ cat=5&post_meta_key=thumbnail’);
=>SQL구문을 파싱합니다. 

2. SELECT * FROM wp_posts WHERE category=5 and post_meta_key=‘thumbnail’
=> 싱글쿼터를 삽입합니다.

3. $query_results = new WP_Query (‘ cat=5&post_meta_key=thumbnail’);
=>결과 및 SQL 쿼리가 WP_Query에 저장!


WP_Query 개체는 생성자의 인수와 일치하는 데이터베이스에서 WordPress 게시물을 검색합니다.

 

 

CODEX set_transient ()

if(false ===($query_results = get_transient('qeury_results')))
 {
 	$query_results = new WP_Query('cat=5&order=random&tag=tech&post_meta_key=thumbnail')
 	set_transient('query_results', $qeury_results, 12 * HOUR_IN_SECONS);
 }

WP는 느린 데이터베이스 쿼리 결과를 데이터베이스에 일시적으로 캐시 할 것을 권장합니다
성능을 향상시키기 위해 느린 데이터베이스 쿼리 결과가 캐싱되어 다음 실행시 생략됩니다.
근데 여기서 잠깐 생각해본다면 "set_transient ()는 데이터베이스에 객체를 어떻게 저장할까?" 라는생각이 들게됩니다.

 

 

 

set_transient() / add_option()

function set_transient($transient, $value, $expiration = 0))) 1
{
	$result = add_option($option, $value ='', $deprecated = '', $autoload);
}
function add_option($option, $value ='', $deprecated = '', $autoload ='yes'))) 2
{
	$serialized_value = maybe_serialize($value); (1)
	$result = $wpdb->qeury($wpdb->prepare("INSERT INTO '$wpdb->options' (...) (2)
        VALUES (%s %s %s") ...", ..., $serialized_value, ...));
}

WP_Query 객체는 $ value에 저장됩니다.
일단 소스를 보면 (1)에  maybe_serialize 가 있는데 이것은 PHP 변수들을 string 으로 만들어 주는 함수입니다. 
그리고 set_transient()을 이용해서 값을 직렬화하는데 사용합니다.
(2) add_option의 autoload는 옵션이 추가되지 않으면 false이고 옵션이 추가되면 true입니다.

WooCommerce

woocommerce는 WordPress 오픈 소스 전자 상거래 플러그인입니다.

 

 

 

 

 

 

Products category=“toasters” sku=“%”

 

 

% prepare() 통해서 첫번째칸에 있는 값의 sku a93..dc 변경이 됩니다.

 

           O:8:”WP_Query”:1{s:3:”sql”;s:100:”SELECT…sku=‘{a93..dc}””;}

 

 

O:8:"WP_Query":1:{s:3:"sql";s:100:"SELECT… sku=‘%‘ ";…;s:7:"content";s:11:"somecontent";}
O:8:"WP_Query":1:{s:3:"sql";s:100:"SELECT… sku=‘%‘ ";…;s:7:"content";s:11:"somecontent";}
O:8:"WP_Query":1:{s:3:"sql";s:100:"SELECT… sku=‘%‘ ";…;s:7:"content";s:11:"some";;i:0;O:8:"EvilClass":0:{}i:1;s:0:"";}

 

O:8:"WP_Query":1:{s:3:"sql";s:100:"SELECT… sku=‘%‘ ";…;s:7:"content";s:11:"some";;i:0;O:8:"EvilClass":0:{}i:1;s:0:"";}





PHP Object injection!!!

'잡동사니 > webhacking' 카테고리의 다른 글

매커니즘  (0) 2022.01.27
unserialized  (0) 2021.12.09
PHP - Unserialize()  (0) 2019.08.16
Comments