$query = $wpdb->prepare( 'update articles set title = %s where id = %d and uid = %d', $_GET['title'], $_GET['id'], get_current_uid());
按正常的业务逻辑,prepare将返回
vsprintf( 'update articles set title = %s where id = %d and uid = %d', array($_GET['title'], $_GET['id'], get_current_uid() )
的执行结果。
但是此时format后的第一个参数($_GET[‘title’])我们完全可控,如果我们使第一个参数为数组,我们就可以控制用户ID,如:$_GET[‘title’] = array(‘title’, ‘id’ ,’xxx’),此时prepare将返回
vsprintf( 'update articles set title = %s where id = %d and uid = %d', array('title', 'id' ,'xxx')
。
此时,一个越权漏洞就产生了。
2). SQL注入
若程序中存在类似下列的代码:
1
2
3
$append = $wpdb->prepare( 'and tag = %s', $_GET['tag']);
$query = $wpdb->prepare( 'select * from articles where uid = %d and cid = %d '.$append, get_current_uid(), $_GET['cid']);
mysql_query($query);
我们使得
tag=%s
,则
$append="and tag = '%sa'"
。此时的
$query
将为
$wpdb->prepare( 'select * from articles where uid = %d and cid = %d and tag = \'%s\'', get_current_uid(), $_GET['cid'])
,经prepare处理后等同于
$query = vsprintf('select * from articles where uid = %d and cid = %d and tag = \'\'%s\'a\'', array(get_current_uid(), $_GET['cid']));
。
此时的%s将处于单引号之外,如果%s可控,将导致SQL注入。此时,就要用到前面1.3部分提到的
Argument numbering/swapping
,我们可以使
tag=%2$s
,但是此时不存在
%s
,经prepare函数处理后,
$query = vsprintf('select * from articles where uid = %d and cid = %d and tag = \'%2$s\'', array(get_current_uid(), $_GET['cid']));
,虽然此时的%2$s经vsprintf函数格式化后将等于
$_GET['cid']
的值,但是参数被包含在引号之内,无法导致SQL注入。
这时我们就需要用到1.3内的
字符串自动补位
。我们使
tag=%2$%s abc
,经prepare处理后
$query = vsprintf('select * from articles where uid = %d and cid = %d and tag = \'%2$\'%s\' abc\'', array(get_current_uid(), $_GET['cid']));
。此时的关键部分为
tag = '%2$'%s' abc'
,此时的
%2$'%s
为格式化标识,里面2代表第二个参数(即
$_GET['cid']
),’%表示用%填充,s表示格式化为字符串,默认的填充位数为0。