-
Notifications
You must be signed in to change notification settings - Fork 339
Description
Checklist (Please check before submitting)
- I reviewed the Contributing Guide.
- I performed a cursory search to see if the bug report is relevant, not redundant, nor in conflict with other tickets.
Describe the bug
A full-chain Remote Code Execution (RCE) vulnerability exists in NASA cFS when deployed with the CF (CCSDS File Delivery Protocol) application. An unauthenticated attacker with network access to the CI_LAB command ingest port can achieve arbitrary code execution as the cFS process — using only UDP packets, with zero prior filesystem access.
The attack exploits three combined weaknesses:
- CF App: No destination path validation in CFDP file reception — An attacker can upload arbitrary files to any writable path via CFDP Metadata PDU.
- CFE_ES: No code signing or integrity verification on
dlopen()—ES_START_APPloads any.sofile without signature checks. - CI_LAB: No authentication on command interface — All commands are accepted via plaintext UDP.
Demonstrated Impact: Bind shell (/bin/sh) spawned on port 4444 as the cFS process, accessible from the network. Full system compromise.
POC Videos:
- Short ver.: https://youtu.be/UfBAwknsYsg
- Long (include target build) ver.: https://youtu.be/Ebdv6whIA8Y
To Reproduce
Steps to reproduce the behavior:
- Clone cFS with CF App
# Clone cFS Draco release
git clone --branch v7.0.0 [https://github.com/nasa/cFS.git](https://github.com/nasa/cFS.git)
cd cFS
git submodule init && git submodule update
cp -r cfe/cmake/sample_defs/ sample_defs
cp cfe/cmake/Makefile.sample Makefile
# Clone CF app
cd apps
git clone --branch v7.0.0 [https://github.com/nasa/CF.git](https://github.com/nasa/CF.git) cf
cd ..
# Add CF to build configuration
sed -i 's/SET(cpu1_APPLIST ci_lab to_lab sch_lab)/SET(cpu1_APPLIST ci_lab to_lab sch_lab cf)/' sample_defs/targets.cmake
# Add CF to startup script
sed -i '/^!/i CFE_APP, cf, CF_AppMain, CF, 90, 16384, 0x0, 0;' sample_defs/cpu1_cfe_es_startup.scr- Build cFS with CF
make SIMULATION=native prep
make
make install
cd build
make mission-cfetables
cd ..- Start cFS
cd build/exe/cpu1
./core-cpu1(Verify CF loaded successfully in the output: CF Initialized. Version 7.0.0.0 and CI_LAB listening on UDP port: 1234)
- Execute the exploit script (
fullchain_rce.py)
(censored)
python3 fullchain_rce.py- Connect to the Bind Shell
nc 127.0.0.1 4444Expected behavior
- The CF application should validate destination paths in CFDP to prevent arbitrary file writes outside of designated directories.
ES_START_APPshould verify the integrity and authenticity (e.g., via code signing) of loaded.somodules before invokingdlopen().- CI_LAB should implement an authentication mechanism on its command interface to prevent unauthorized packet execution.
Code snips
Root Cause #1: CFDP Destination Path Not Validated (CF App)
apps/cf/fsw/src/cf_cfdp.c
When the CF app receives a CFDP Metadata PDU, it extracts the destination filename from the PDU and stores it directly — without any path validation, directory restriction, or whitelist check.
// cf_cfdp.c — CF_CFDP_CopyStringFromLV()
int CF_CFDP_CopyStringFromLV(char *buf, size_t buf_maxsz, const CF_Logical_Lv_t *src_lv)
{
if (src_lv->length < buf_maxsz)
{
memcpy(buf, src_lv->data_ptr, src_lv->length); // ← Raw memcpy, no validation
buf[src_lv->length] = 0;
return src_lv->length;
}
buf[0] = 0;
return CF_ERROR;
}
// cf_cfdp.c — CF_CFDP_RecvMd() (partial)
lv_ret = CF_CFDP_CopyStringFromLV(
txn->history->fnames.dst_filename,
sizeof(txn->history->fnames.dst_filename),
&md->dest_filename // ← Attacker-controlled from Metadata PDU
);Root Cause #2: No Code Signing on Dynamic Module Loading (CFE_ES)
cfe/modules/es/fsw/src/cfe_es_task.c
The ES_START_APP command (Command Code 4) loads any .so file via dlopen() without signature verification, path whitelisting, or hash comparison.
// cfe_es_task.c — CFE_ES_StartAppCmd() (critical path)
Result = CFE_ES_AppCreate(&AppID, LocalAppName, &StartParams);
// → calls CFE_ES_LoadModule()
// → calls OS_ModuleLoad()
// → calls dlopen(filename) ← No signature check before thisSystem observed on:
- Hardware: Ubuntu Host Architecture (Tested on x86_64, Payload targets aarch64/x86_64 depending on local compiler)
- OS: Ubuntu 24.04.4 LTS (Noble Numbat)
- Versions:
- cFS v7.0.0 (Draco) - Commit:
b4ec679b2fd9d825610515ceb186cbfa80c60cfc - CF App v7.0.0 - Commit:
92baf07dc04d92cb388d899119df060126f708a0 - cFE v7.0.0+dev0 (Included in cFS Draco)
- OSAL v7.0.0 (Included in cFS Draco)
- cFS v7.0.0 (Draco) - Commit:
Additional context
Upon successful exploitation, the following Check Result outputs are observable from the target:
CF R1(23:1): successfully retained file as /cf/pwned.so
Started PWNED from /cf/pwned.so, AppID = 1114123
Screenshot of successful remote bind shell session:
Reporter Info
juntheworld (junhak lee)