Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding more tests #135

Merged
merged 4 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions docs/TestFeatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,20 @@ $ make PROCNAME="myprocname"
$ make check-kovid
```

## Linux Kernel 5.10

1. Hide itself

TODO
## Testing status

Here are information about testing of the features available.

### Linux Kernel 5.10

| Feature | Tested | Regression Test |
| :--------------------------------------------------| :------------------------------| :--------------------------------- |
| Hide process | Yes | features/hide-pid.test |
| Extract base address of a running process | Yes | features/extract-base-address.test |
| anti-rk's that are available (bpf-hookdetect) | No (hard to test on qemu) | None |
| anti-rk's that are available (rkspotter) | No (build for non host kernel) | None |
| anti-rk's that are available (rkbreaker) | No (build for non host kernel) | None |
| Simple netcat reverse shell | No (understand bdclient) | None |
| Log tty keys and steal passwords over SSH (and FTP)| No (understand bdclient) | None |
| Simple persistence using ELF infection with Volundr| No (understand bdclient) | None |
| Hide pre-defined network application | Yes | None |
129 changes: 65 additions & 64 deletions test/Artefacts/qemu-runner.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,93 +20,97 @@ if [[ ! -f "$KERNEL_IMAGE" || ! -f "$ROOT_FS" || ! -f "$KOVID_MODULE" ]]; then
exit 1
fi

# Create a writable copy of the root filesystem
TEMP_ROOTFS="/tmp/rootfs_writable.ext2"
cp "${ROOT_FS}" "${TEMP_ROOTFS}"

# Cleanup function to terminate QEMU and remove temporary files
cleanup() {
echo "Cleaning up..."
if [[ -n "$QEMU_PID" ]]; then
kill -SIGTERM "$QEMU_PID" 2>/dev/null
wait "$QEMU_PID" 2>/dev/null
fi
rm -f "$TEMP_ROOTFS"
echo "QEMU shut down and temporary files cleaned."
}

# Trap to ensure cleanup runs on exit
trap cleanup EXIT INT ERR

# Start QEMU in the background
qemu-system-x86_64 \
-kernel "$KERNEL_IMAGE" \
-append "root=/dev/sda rw console=ttyS0,115200 init=/sbin/init" \
-drive format=raw,file="$TEMP_ROOTFS" \
-device e1000,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::${SSH_PORT}-:22 \
$QEMU_FLAGS &> qemu_output.log &

QEMU_PID=$!

# Wait for SSH to be available
echo "Waiting for QEMU && SSH to be ready..."
for i in {1..20}; do
if ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p ${SSH_PORT} root@localhost 'echo SSH is ready'; then
echo "SSH connection to QEMU established."
break
fi
echo "QEMU && SSH not ready, retrying in 3 seconds... (Attempt $i of 20)"
sleep 3
done

# Final check if SSH is still not available
if ! ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p ${SSH_PORT} root@localhost 'echo SSH is ready'; then
echo "Failed to establish SSH connection to QEMU after multiple attempts. Exiting..."
exit 1
fi

# Transfer kovid.ko to QEMU and load it
echo "Transferring and loading kovid.ko on QEMU..."
scp -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -P ${SSH_PORT} "$KOVID_MODULE" root@localhost:"$RFS_PATH/kovid.ko" || {
echo "Failed to transfer kovid.ko to QEMU."
exit 1
}
ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p ${SSH_PORT} root@localhost "insmod $RFS_PATH/kovid.ko" || {
echo "Failed to load kovid.ko on QEMU."
exit 1
}

# Function to execute each test script on QEMU
execute_test_script() {
TEST_SCRIPT=$1 # Path to the test script on the host
TEST_LOG="$(basename "${TEST_SCRIPT%.sh}.log")" # Log file name on the host

# Create a writable copy of the root filesystem
TEMP_ROOTFS="/tmp/rootfs_writable.ext2"
cp "${ROOT_FS}" "${TEMP_ROOTFS}"

# Start QEMU in the background
qemu-system-x86_64 \
-kernel "$KERNEL_IMAGE" \
-append "root=/dev/sda rw console=ttyS0,115200 init=/sbin/init" \
-drive format=raw,file="$TEMP_ROOTFS" \
-device e1000,netdev=net0 \
-netdev user,id=net0,hostfwd=tcp::${SSH_PORT}-:22 \
$QEMU_FLAGS &> qemu_output.log &

QEMU_PID=$!

# Wait for SSH to be available
echo "Waiting for QEMU && SSH to be ready..."
for i in {1..20}; do
if ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p ${SSH_PORT} root@localhost 'echo SSH is ready'; then
echo "SSH connection to QEMU established."
break
fi
echo "QEMU && SSH not ready, retrying in 3 seconds... (Attempt $i of 20)"
sleep 3
done

# Final check if SSH is still not available
if ! ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o ConnectTimeout=5 -p ${SSH_PORT} root@localhost 'echo SSH is ready'; then
echo "Failed to establish SSH connection to QEMU after multiple attempts. Exiting..."
kill -SIGTERM "$QEMU_PID" 2>/dev/null
rm -f "$TEMP_ROOTFS"
exit 1
fi

# Transfer kovid.ko to QEMU and load it
echo "Transferring and loading kovid.ko on QEMU..."
scp -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -P ${SSH_PORT} "$KOVID_MODULE" root@localhost:"$RFS_PATH/kovid.ko" || {
echo "Failed to transfer kovid.ko to QEMU."
kill -SIGTERM "$QEMU_PID" 2>/dev/null
rm -f "$TEMP_ROOTFS"
exit 1
}
ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p ${SSH_PORT} root@localhost "insmod $RFS_PATH/kovid.ko" || {
echo "Failed to load kovid.ko on QEMU."
kill -SIGTERM "$QEMU_PID" 2>/dev/null
rm -f "$TEMP_ROOTFS"
exit 1
}

echo "Running test script $(basename "$TEST_SCRIPT") on QEMU..."

# Transfer the test script to QEMU
scp -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -P ${SSH_PORT} "$TEST_SCRIPT" root@localhost:"$RFS_PATH/$(basename "$TEST_SCRIPT")" || {
echo "Failed to transfer test script $(basename "$TEST_SCRIPT") to QEMU."
kill -SIGTERM "$QEMU_PID" 2>/dev/null
rm -f "$TEMP_ROOTFS"
exit 1
}

# Run the test script on QEMU in the background, capturing output and returning immediately
# Run the test script on QEMU, capturing output and returning immediately
ssh -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -p ${SSH_PORT} root@localhost "nohup sh -c 'chmod +x $RFS_PATH/$(basename "$TEST_SCRIPT") && $RFS_PATH/$(basename "$TEST_SCRIPT")' > $RFS_PATH/$TEST_LOG 2>&1 &" || {
echo "Failed to execute test script $(basename "$TEST_SCRIPT") on QEMU."
kill -SIGTERM "$QEMU_PID" 2>/dev/null
rm -f "$TEMP_ROOTFS"
exit 1
}

# Wait a brief moment to ensure command starts
sleep 1
sleep 1 # Wait briefly to ensure the test script starts

# Retrieve the log file from QEMU
scp -i "$SSH_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -P ${SSH_PORT} root@localhost:"$RFS_PATH/$TEST_LOG" . || {
echo "Failed to retrieve log file $TEST_LOG from QEMU."
kill -SIGTERM "$QEMU_PID" 2>/dev/null
rm -f "$TEMP_ROOTFS"
exit 1
}

# Ensure the completion message is displayed
# Display completion message
echo "Test script $(basename "$TEST_SCRIPT") completed. Output saved to $TEST_LOG."

# Cleanup for each test
echo "Cleaning up QEMU for $(basename "$TEST_SCRIPT")..."
kill -SIGTERM "$QEMU_PID" 2>/dev/null
wait "$QEMU_PID" 2>/dev/null
rm -f "$TEMP_ROOTFS"
echo "QEMU shut down and temporary files cleaned for $(basename "$TEST_SCRIPT")."
}

# Loop through each .test file and corresponding script in TEST_DIR
Expand All @@ -119,6 +123,3 @@ for TEST_FILE in "$TEST_DIR"/*.test; do
echo "Skipping $(basename "$TEST_SCRIPT") as it or the .test file is missing."
fi
done

# After all tests are done, shut down QEMU
cleanup
22 changes: 22 additions & 0 deletions test/features/extract-base-address.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/bin/sh

insmod kovid.ko

# The kovid trick
kill -CONT 31337

# Run the a.out executable in the background
./a.out &
AOUT_PID=$! # Capture the PID of a.out

# Wait briefly to ensure a.out has started
sleep 1

# Output the PID (for debugging or verification)
echo "PID of a.out is $AOUT_PID"

echo "-b $AOUT_PID" > /proc/myprocname

cat /proc/myprocname

rmmod kovid.ko
5 changes: 5 additions & 0 deletions test/features/extract-base-address.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# RUN: FileCheck-18 --input-file=%kovid_testdir/extract-base-address.log %s

# CHECK: sh: can't kill pid 31337: No such process
## We expect an address like `55e648a65000`
# CHECK: 55{{.*}}
6 changes: 6 additions & 0 deletions test/features/hide-pid.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#!/bin/sh

insmod kovid.ko

# The kovid trick
kill -CONT 31337

Expand All @@ -17,3 +19,7 @@ echo $AOUT_PID > /proc/myprocname

# Attempt to kill the process by PID and log the output
kill -9 "$AOUT_PID"

rmmod kovid.ko

kill -9 "$AOUT_PID"
Loading