Valve · Report #763403
[GoldSrc] RCE via malformed BSP file
Validstatus
highseverity
$450bounty
24upvotes
19 Aug 2020disclosed
Summary
#Description RCE can be achieved via a malformed BSP file due to the lack of length validation when copying data from the BSP file into a stack based buffer.
#POC
- Place the attached BSP {F666628} in the maps directory of the chosen GoldSrc game (czero/maps, cstrike/maps, tfc/maps, etc..)
- Launch the game and bring up the console with ~
- Type in
map de_RCEand press enter - View calc pop
#Vulnerable Code
Within the following function, COM_FileBase copies data from pszWadFile into wadName without any length validation which leads to a buffer overflow.
qboolean TEX_InitFromWad(char *path)
{
char *pszWadFile;
FileHandle_t texfile;
char szTmpPath[1024];
char wadName[260];
char wadPath[260];
wadinfo_t header;
Q_strncpy(szTmpPath, path, 1022);
szTmpPath[1022] = 0;
if (!Q_strchr(szTmpPath, ';'))
Q_strcat(szTmpPath, ";");
for (pszWadFile = strtok(szTmpPath, ";"); pszWadFile; pszWadFile = strtok(NULL, ";"))
{
ForwardSlashes(pszWadFile);
COM_FileBase(pszWadFile, wadName);//Vulnerable Function
Q_snprintf(wadPath, 0x100u, "%s", wadName);
COM_DefaultExtension(wadPath, ".wad");
if (Q_strstr(wadName, "pldecal") || Q_strstr(wadName, "tempdecal"))
continue;
texfile = FS_Open(wadPath, "rb");
texfiles[nTexFiles++] = texfile;
if (!texfile)
Sys_Error("%s: couldn't open %s\n", __func__, wadPath);
Con_DPrintf("Using WAD File: %s\n", wadPath);
SafeRead(texfile, &header, 12);
if (Q_strncmp(header.identification, "WAD2", 4) && Q_strncmp(header.identification, "WAD3", 4))
Sys_Error("%s: %s isn't a wadfile", __func__, wadPath);
header.numlumps = LittleLong(header.numlumps);
header.infotableofs = LittleLong(header.infotableofs);
FS_Seek(texfile, header.infotableofs, FILESYSTEM_SEEK_HEAD);
lumpinfo = (texlumpinfo_t *)Mem_Realloc(lumpinfo, sizeof(texlumpinfo_t) * (header.numlumps + nTexLumps));
for (int i = 0; i < header.numlumps; i++, nTexLumps++)
{
SafeRead(texfile, &lumpinfo[nTexLumps], sizeof(lumpinfo_t));
CleanupName(lumpinfo[nTexLumps].lump.name, lumpinfo[nTexLumps].lump.name);
lumpinfo[nTexLumps].lump.filepos = LittleLong(lumpinfo[nTexLumps].lump.filepos);
lumpinfo[nTexLumps].lump.disksize = LittleLong(lumpinfo[nTexLumps].lump.disksize);
lumpinfo[nTexLumps].iTexFile = nTexFiles - 1;
}
}
qsort(lumpinfo, nTexLumps, sizeof(texlumpinfo_t), lump_sorter);
return 1;
}
Impact
RCE can be used to execute any arbitrary code that an attacker could want to execute on any victim of choice.
How it was found
The write-up for this report has not been downloaded yet, or the program disclosed it without one. Read it on HackerOne.