├── .idea ├── .gitignore ├── artifacts │ └── SqlDownload_jar.xml ├── compiler.xml ├── encodings.xml ├── jarRepositories.xml ├── misc.xml └── uiDesigner.xml ├── README.md ├── pom.xml └── src └── main ├── java └── com │ └── google │ └── SQLDownload.java └── resources └── META-INF └── MANIFEST.MF /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /.idea/artifacts/SqlDownload_jar.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | $PROJECT_DIR$/out/artifacts/SqlDownload_jar 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SQLDownload - 内网大型数据下载的解决方案 2 | 3 | 内网大型数据拖库解决方案,隧道不稳定时将内网数据库保存为csv格式文件 4 | 5 | **郑重声明:文中所涉及的技术、思路和工具仅供以安全为目的的学习交流使用,任何人不得将其用于非法用途以及盈利等目的,否则后果自行承担** 。 6 | 7 |

8 | 9 |

工具介绍 · 使用说明 · 注意事项 · 技术交流

10 | 11 |
12 | 13 |

工具介绍

14 | 15 | 该工具诞生背景: 16 | 17 | 在打内网时候会有隧道不稳定情况无论是数据读取还是数据下载都会被影响(人穷vps垃圾),所以为了解决这个问题,写了这个小工具内网本地执行,为应对多种场景提供多种选项解决。 18 | 19 | 该工具应用场景: 20 | 21 | 1. 数据库取证 22 | 2. 数据库读取/下载 23 | 3. 联表导出 24 | 25 | 该工具的使用方案: 26 | 27 | 1. 配置文件读取`info.txt` (优先) 28 | 2. 终端交互写入 29 | 3. 配置与终端混合交互 30 | 31 |
32 | 33 |

使用说明

34 | 35 | **配置文件导入**: 36 | 37 | 在当前目录下保存一个info.txt 38 | 39 | ```txt 40 | # jdbc mysql url 41 | db_url=jdbc:mysql://localhost:3306/a 42 | # jdbc mysql username 43 | db_user=root 44 | # jdbc mysql password 45 | db_passwd=123456 46 | # function mode 47 | db_function=1 48 | ``` 49 | 50 | ![image-20231101102158773](https://cdn.jsdelivr.net/gh/z-bool/images@master/img/image-20231101102158773.png) 51 | 52 | **交互模式导入**: 53 | 54 | 无配置文件情况下 55 | 56 | ![image-20231101103319629](https://cdn.jsdelivr.net/gh/z-bool/images@master/img/image-20231101103319629.png) 57 | 58 | **混合模式:** 59 | 60 | 文本配置下,部分不填,解决连接固定减少多次输入的情况,通过交互来解决。 61 | 62 | ```txt 63 | # jdbc mysql url 64 | db_url=jdbc:mysql://localhost:3306/a 65 | # jdbc mysql username 66 | db_user=root 67 | # jdbc mysql password 68 | db_passwd=123456 69 | # function mode 70 | db_function= 71 | ``` 72 | 73 | ![image-20231101104142247](https://cdn.jsdelivr.net/gh/z-bool/images@master/img/image-20231101104142247.png) 74 | 75 | image-20231101104212439 76 | 77 | 将每张表保存拖到当前目录下对应表名的csv文件中。 78 | 79 | **功能介绍**: 80 | 81 | 1. Retrieve the names of all database repositories under the connection. (查询当前连接的所有数据库名) 82 | 2. Read all tables and fields of the specified database.(查询当前数据库的所有表和字段) 83 | 3. Drag all the contents of the specified library.(下载当前数据库的所有表数据) 84 | 4. Terminal prints the first 50 records of SQL execution results for debugging purposes.(限制下的SQL查询,结果只显示50条且展示在终端上) 85 | 5. Save SQL execution results with unlimited queries.(无限制的SQL查询,结果保存在当前目录下的6位随机名字的csv文件中) 86 | 87 | **SQL功能举例**: 88 | 89 | 限制下的SQL执行展示 90 | 91 | ![image-20231101105055692](https://cdn.jsdelivr.net/gh/z-bool/images@master/img/image-20231101105055692.png) 92 | 93 | 无限制下的SQL结果展示 94 | 95 | ![image-20231101105227888](https://cdn.jsdelivr.net/gh/z-bool/images@master/img/image-20231101105227888.png) 96 | 97 | ![image-20231101105241607](https://cdn.jsdelivr.net/gh/z-bool/images@master/img/image-20231101105241607.png) 98 | 99 | ![image-20231101105305861](https://cdn.jsdelivr.net/gh/z-bool/images@master/img/image-20231101105305861.png) 100 | 101 |
102 | 103 |

注意事项

104 | 105 | 合理利用,正常还是隧道正常连方便,这是为了解决数据过大的情况。 106 | 107 |
108 | 109 |

技术交流

110 | 111 | 阿呆攻防公众号 112 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | org.example 8 | SqlDownload 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 8 13 | 8 14 | UTF-8 15 | 16 | 17 | 18 | 19 | mysql 20 | mysql-connector-java 21 | 8.0.29 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/main/java/com/google/SQLDownload.java: -------------------------------------------------------------------------------- 1 | package com.google; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileReader; 5 | import java.io.FileWriter; 6 | import java.io.IOException; 7 | import java.sql.*; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.Properties; 11 | import java.util.Scanner; 12 | 13 | public class SQLDownload { 14 | 15 | public static String DBURL = ""; 16 | public static String DBUSER = ""; 17 | public static String DBPASSWORD = ""; 18 | 19 | public static Integer DBFunction = 0; 20 | 21 | public static Scanner scanner = new Scanner(System.in); 22 | 23 | public static Connection connection = null; 24 | 25 | public static void main(String[] args) throws SQLException { 26 | 27 | readConfigFile(); 28 | System.out.print("If you want to exit during configuration, please type (exit)\n"); 29 | if (DBURL.equals("")){ 30 | System.out.print("Please enter your MySQL connection URL:\n"); 31 | System.out.print("-: "); 32 | 33 | DBURL = isNotExitString(); 34 | } 35 | if (DBUSER.equals("")){ 36 | System.out.println("Please enter your MySQL username:"); 37 | System.out.print("-: "); 38 | DBUSER = isNotExitString(); 39 | } 40 | if (DBPASSWORD.equals("")){ 41 | System.out.println("Please enter your MySQL password:"); 42 | System.out.print("-: "); 43 | DBPASSWORD = isNotExitString(); 44 | } 45 | if (DBFunction == 0){ 46 | System.out.println("Please confirm the serial number of the function you want to select:"); 47 | System.out.println("1. Retrieve the names of all database repositories under the connection."); 48 | System.out.println("2. Read all tables and fields of the specified database."); 49 | System.out.println("3. Drag all the contents of the specified library."); 50 | System.out.println("4. Terminal prints the first 50 records of SQL execution results for debugging purposes."); 51 | System.out.println("5. Save SQL execution results with unlimited queries."); 52 | System.out.print("-: "); 53 | DBFunction = Integer.parseInt(isNotExitString()); 54 | } 55 | 56 | 57 | 58 | try { 59 | if (SQLDownload.connection == null && !DBURL.equals("") && !DBUSER.equals("") ){ 60 | SQLDownload.connection = DriverManager.getConnection(DBURL, DBUSER, DBPASSWORD); 61 | } 62 | 63 | if (DBFunction == 1){ 64 | chooseOne(SQLDownload.connection); 65 | }else if (DBFunction == 2){ 66 | chooseTwo(SQLDownload.connection); 67 | }else if (DBFunction == 3) { 68 | assert SQLDownload.connection != null; 69 | chooseThree(SQLDownload.connection); 70 | } else if (DBFunction ==4 || DBFunction == 5) { 71 | WaitForSQLImport(); 72 | } 73 | 74 | scanner.close(); 75 | connection.close(); 76 | } catch (SQLException e) { 77 | e.printStackTrace(); 78 | } 79 | 80 | } 81 | 82 | public static void WaitForSQLImport() throws SQLException { 83 | while (true) { 84 | System.out.println("Please enter your SQL, if you want to out, please enter \"exit\":"); 85 | System.out.print("> "); 86 | String sql = scanner.nextLine(); 87 | if (sql.equalsIgnoreCase("exit")) { 88 | break; 89 | } 90 | 91 | if (DBFunction == 4){ 92 | assert SQLDownload.connection != null; 93 | executeSQL(SQLDownload.connection, sql,true); 94 | }else if (DBFunction == 5){ 95 | assert SQLDownload.connection != null; 96 | executeSQL(SQLDownload.connection, sql,false); 97 | } 98 | } 99 | } 100 | 101 | public static String isNotExitString(){ 102 | String str = scanner.nextLine(); 103 | if (str.equals("exit")){ 104 | System.exit(0); 105 | } 106 | return str; 107 | } 108 | 109 | public static void chooseOne(Connection connection) throws SQLException { 110 | listAccessibleDatabases(connection); 111 | } 112 | 113 | public static void chooseTwo(Connection connection) throws SQLException{ 114 | getDatabaseMetadata(connection); 115 | } 116 | 117 | public static void chooseThree(Connection connection) throws SQLException{ 118 | Statement statement = connection.createStatement(); 119 | 120 | ResultSet tables = connection.getMetaData().getTables( connection.getCatalog(), null, null, new String[] {"TABLE"}); 121 | 122 | 123 | while (tables.next()) { 124 | String tableName = tables.getString("TABLE_NAME"); 125 | String fileName = tableName + ".csv"; 126 | 127 | // 执行查询以获取表数据 128 | ResultSet resultSet = statement.executeQuery("SELECT * FROM " + tableName); 129 | ResultSetMetaData metaData = resultSet.getMetaData(); 130 | 131 | try (FileWriter writer = new FileWriter(fileName)) { 132 | for (int i = 1; i <= metaData.getColumnCount(); i++) { 133 | writer.append(metaData.getColumnName(i)); 134 | if (i < metaData.getColumnCount()) { 135 | writer.append(","); 136 | } 137 | } 138 | writer.append("\n"); 139 | 140 | while (resultSet.next()) { 141 | for (int i = 1; i <= metaData.getColumnCount(); i++) { 142 | writer.append(resultSet.getString(i)); 143 | if (i < metaData.getColumnCount()) { 144 | writer.append(","); 145 | } 146 | } 147 | writer.append("\n"); 148 | } 149 | } catch (IOException e) { 150 | e.printStackTrace(); 151 | } 152 | } 153 | } 154 | 155 | public static void executeSQL(Connection connection, String sql, boolean isLimit) throws SQLException { 156 | Statement statement = connection.createStatement(); 157 | if (!sql.endsWith(";")) { 158 | sql += ";"; 159 | } 160 | 161 | if (isLimit) { 162 | sql = sql.substring(0, sql.length() - 1) + " LIMIT 50;"; 163 | } 164 | 165 | ResultSet resultSet = statement.executeQuery(sql); 166 | 167 | if (isLimit) { 168 | printResultSetToConsole(resultSet); 169 | } else { 170 | saveResultSetToCSV(resultSet); 171 | } 172 | 173 | resultSet.close(); 174 | statement.close(); 175 | } 176 | 177 | private static void printResultSetToConsole(ResultSet resultSet) throws SQLException { 178 | for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { 179 | System.out.print(resultSet.getMetaData().getColumnName(i)); 180 | if (i < resultSet.getMetaData().getColumnCount()) { 181 | System.out.print(", "); 182 | } 183 | } 184 | System.out.println("\n"); 185 | while (resultSet.next()) { 186 | for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { 187 | System.out.print(resultSet.getString(i)); 188 | if (i < resultSet.getMetaData().getColumnCount()) { 189 | System.out.print(", "); 190 | } 191 | } 192 | System.out.println("\n"); 193 | } 194 | } 195 | 196 | private static void saveResultSetToCSV(ResultSet resultSet) throws SQLException { 197 | String fileName = generateRandomFileName() + ".csv"; 198 | 199 | try (FileWriter fileWriter = new FileWriter(fileName)) { 200 | for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { 201 | fileWriter.append(resultSet.getMetaData().getColumnName(i)); 202 | if (i < resultSet.getMetaData().getColumnCount()) { 203 | fileWriter.append(","); 204 | } 205 | } 206 | fileWriter.append("\n"); 207 | 208 | while (resultSet.next()) { 209 | for (int i = 1; i <= resultSet.getMetaData().getColumnCount(); i++) { 210 | fileWriter.append(resultSet.getString(i)); 211 | if (i < resultSet.getMetaData().getColumnCount()) { 212 | fileWriter.append(","); 213 | } 214 | } 215 | fileWriter.append("\n"); 216 | } 217 | } catch (IOException e) { 218 | e.printStackTrace(); 219 | } 220 | } 221 | 222 | private static String generateRandomFileName() { 223 | String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; 224 | StringBuilder randomFileName = new StringBuilder(); 225 | for (int i = 0; i < 6; i++) { 226 | int index = (int) (Math.random() * chars.length()); 227 | randomFileName.append(chars.charAt(index)); 228 | } 229 | return randomFileName.toString(); 230 | } 231 | 232 | 233 | 234 | public static void readConfigFile() { 235 | try (BufferedReader br = new BufferedReader(new FileReader("info.txt"))) { 236 | Properties properties = new Properties(); 237 | properties.load(br); 238 | DBURL = properties.getProperty("db_url"); 239 | DBUSER = properties.getProperty("db_user"); 240 | DBPASSWORD = properties.getProperty("db_passwd"); 241 | String db_function = properties.getProperty("db_function"); 242 | if (!db_function.equals("")){ 243 | DBFunction = Integer.parseInt(db_function); 244 | } 245 | 246 | 247 | } catch (IOException e) { 248 | System.out.println("IO Error:" + e.getMessage()); 249 | } 250 | } 251 | public static void listAccessibleDatabases(Connection connection) throws SQLException { 252 | Statement statement = connection.createStatement(); 253 | String query = "SHOW DATABASES"; 254 | ResultSet resultSet = statement.executeQuery(query); 255 | 256 | while (resultSet.next()) { 257 | String databaseName = resultSet.getString(1); 258 | if (!(databaseName.equals("information_schema") || databaseName.equals("performance_schema") || databaseName.equals("mysql"))){ 259 | System.out.println("Database: " + databaseName); 260 | } 261 | } 262 | 263 | resultSet.close(); 264 | statement.close(); 265 | } 266 | 267 | public static void getDatabaseMetadata(Connection connection) throws SQLException { 268 | System.out.println("Current database name: " + connection.getCatalog()); 269 | DatabaseMetaData metaData = connection.getMetaData(); 270 | ResultSet tables = metaData.getTables(connection.getCatalog(), null, null, new String[] {"TABLE"}); 271 | 272 | while (tables.next()) { 273 | String tableName = tables.getString("TABLE_NAME"); 274 | System.out.println("Table: " + tableName); 275 | 276 | ResultSet columns = metaData.getColumns(null, null, tableName, null); 277 | 278 | List columnNames = new ArrayList<>(); 279 | while (columns.next()) { 280 | String columnName = columns.getString("COLUMN_NAME"); 281 | columnNames.add(columnName); 282 | } 283 | 284 | System.out.println("Columns: " + String.join(", ", columnNames)); 285 | 286 | } 287 | } 288 | 289 | } 290 | 291 | 292 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: com.google.SQLDownload 3 | 4 | --------------------------------------------------------------------------------