diff --git a/README.md b/README.md index aaec2b1f..1f6d2d02 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ Details on how to create checkpoints with the help of [CRIU][criu] can be found ## Usage +### `show` sub-command + To display an overview of a checkpoint archive you can just use `checkpointctl show`: @@ -41,6 +43,8 @@ $ checkpointctl show /var/lib/kubelet/checkpoints/checkpoint-counters_default-co +-----------+------------------------------------+--------------+---------+--------------------------------+--------+------------+------------+ ``` +### `inspect` sub-command + To retrieve low-level information about a container checkpoint, use the `checkpointctl inspect` command: ```console @@ -64,6 +68,91 @@ awesome_booth For a complete list of flags supported, use `checkpointctl inspect --help`. +### `memparse` sub-command + +To perform memory analysis of container checkpoints, you can use the `checkpointctl memparse` command. + +```console +$ checkpointctl memparse /path/to/checkpoints/jira.tar.gz --pid=1 | less + +Displaying memory pages content for Process ID 1 from checkpoint: /home/behouba/checkpoints/jira.tar.gz + +Address Hexadecimal ASCII +------------------------------------------------------------------------------------- +00005633bb080000 f3 0f 1e fa 48 83 ec 08 48 8b 05 d1 4f 00 00 48 |....H...H...O..H| +00005633bb080010 85 c0 74 02 ff d0 48 83 c4 08 c3 00 00 00 00 00 |..t...H.........| +00005633bb080020 ff 35 b2 4e 00 00 f2 ff 25 b3 4e 00 00 0f 1f 00 |.5.N....%.N.....| +00005633bb080030 f3 0f 1e fa 68 00 00 00 00 f2 e9 e1 ff ff ff 90 |....h...........| +* +00005633bb0800a0 f3 0f 1e fa 68 07 00 00 00 f2 e9 71 ff ff ff 90 |....h......q....| +00005633bb0800b0 f3 0f 1e fa 68 08 00 00 00 f2 e9 61 ff ff ff 90 |....h......a....| +00005633bb0800c0 f3 0f 1e fa 68 09 00 00 00 f2 e9 51 ff ff ff 90 |....h......Q....| +00005633bb0800d0 f3 0f 1e fa 68 0a 00 00 00 f2 e9 41 ff ff ff 90 |....h......A....| +00005633bb0800e0 f3 0f 1e fa 68 0b 00 00 00 f2 e9 31 ff ff ff 90 |....h......1....| +``` + +Here's an example of memory analysis of a PostgreSQL container. In this case, we start a PostgreSQL container with a password set to 'mysecret'. Then, we create a checkpoint of the container and use the `memparse` to find the stored password. + +```console +$ sudo podman run --name postgres -e POSTGRES_PASSWORD=mysecret -d postgres +$ sudo podman container checkpoint -l --export=/tmp/postgres.tar.gz +$ sudo checkpointctl memparse --pid 1 /tmp/postgres.tar.gz | grep -B 1 -A 1 mysecret +000055dd725c1e60 50 4f 53 54 47 52 45 53 5f 50 41 53 53 57 4f 52 |POSTGRES_PASSWOR| +000055dd725c1e70 44 3d 6d 79 73 65 63 72 65 74 00 00 00 00 00 00 |D=mysecret......| +000055dd725c1e80 00 00 00 00 00 00 00 00 31 00 00 00 00 00 00 00 |........1.......| +``` + +Here's another scenario, of memory analysis for a web application container. We start a vulnerable web application container, perform an arbitrary code execution attack, create a checkpoint for forensic analysis while leaving the container running, and finally analyze the checkpoint memory to identify the injected code. + +```console +# Start vulnerable web application +$ sudo podman run --name dsvw -p 1234:8000 -d quay.io/rst0git/dsvw + +# Perform arbitrary code execution attack: $(echo secret) +$ curl "http://localhost:1234/?domain=www.google.com%3B%20echo%20secret" +nslookup: can't resolve '(null)': Name does not resolve + +Name: www.google.com +Address 1: 142.250.187.228 lhr25s34-in-f4.1e100.net +Address 2: 2a00:1450:4009:820::2004 lhr25s34-in-x04.1e100.net +secret +(reverse-i-search)`': ^C + +# Create a checkpoint for forensic analysis and leave the container running +$ sudo podman container checkpoint --leave-running -l -e /tmp/dsvw.tar + +# Analyse checkpoint memory to identify the attacker's injected code +$ sudo checkpointctl memparse --pid 1 /tmp/dsvw.tar | grep 'echo secret' +00007faac5711f60 6f 6d 3b 20 65 63 68 6f 20 73 65 63 72 65 74 00 |om; echo secret.| +``` + +For larger processes, it's recommended to write the contents of process memory pages to a file rather than standard output. + +To get an overview of process memory sizes within the checkpoint, run `checkpointctl memparse` without arguments. + +```console +$ sudo ./checkpointctl memparse /tmp/jira.tar.gz + +Displaying processes memory sizes from /tmp/jira.tar.gz + ++-----+--------------+-------------+ +| PID | PROCESS NAME | MEMORY SIZE | ++-----+--------------+-------------+ +| 1 | tini | 100.0 KiB | ++-----+--------------+-------------+ +| 2 | java | 553.5 MiB | ++-----+--------------+-------------+ +``` + +In this case given the large size of the java process, it is better to write it output to a file. + +```console +$ sudo ./checkpointctl memparse --pid=2 /tmp/jira.tar.gz --output=/tmp/java-memory-pages.txt +Writing memory pages content for process ID 2 from checkpoint: /tmp/jira.tar.gz to file: /tmp/java-memory-pages.txt... +``` + +Please note that writing large memory pages to a file can take several minutes. + ## Installing from source code 1. Clone the repository.