attackmap-analyzer-c 0.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,167 @@
1
+ Metadata-Version: 2.4
2
+ Name: attackmap-analyzer-c
3
+ Version: 0.2.0
4
+ Summary: C ecosystem analyzer plugin for AttackMap (libmicrohttpd, civetweb, mongoose; libcurl; OpenSSL/mbedTLS/libsodium; sqlite3/libpq/mysql/hiredis/mongoc).
5
+ Author: AttackMap Contributors
6
+ Author-email: Matthew Davis <mlaify@mlaify.io>
7
+ Maintainer-email: Matthew Davis <mlaify@mlaify.io>
8
+ License-Expression: MIT
9
+ Project-URL: Homepage, https://github.com/mlaify/attackmap-analyzer-c
10
+ Project-URL: Repository, https://github.com/mlaify/attackmap-analyzer-c
11
+ Project-URL: Issues, https://github.com/mlaify/attackmap-analyzer-c/issues
12
+ Project-URL: Changelog, https://github.com/mlaify/attackmap-analyzer-c/blob/main/CHANGELOG.md
13
+ Project-URL: AttackMap core, https://github.com/mlaify/AttackMap
14
+ Keywords: security,static-analysis,appsec,defensive-security,attackmap,attackmap-plugin
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Intended Audience :: Information Technology
18
+ Classifier: Intended Audience :: System Administrators
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3 :: Only
25
+ Classifier: Topic :: Security
26
+ Classifier: Topic :: Software Development :: Quality Assurance
27
+ Classifier: Typing :: Typed
28
+ Requires-Python: >=3.11
29
+ Description-Content-Type: text/markdown
30
+ License-File: LICENSE
31
+ Requires-Dist: pydantic>=2.7.0
32
+ Provides-Extra: core
33
+ Requires-Dist: attackmap>=0.6.0; extra == "core"
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
36
+ Requires-Dist: build>=1.2.0; extra == "dev"
37
+ Requires-Dist: attackmap>=0.6.0; extra == "dev"
38
+ Dynamic: license-file
39
+
40
+ # attackmap-analyzer-c
41
+
42
+ > [!IMPORTANT]
43
+ > **Active development, slow pace.** AttackMap is under active development, but
44
+ > progress may be slow until more contributors or co-maintainers join. Help is
45
+ > very welcome with the core engine, an analyzer, the macOS app, or the docs —
46
+ > see [CONTRIBUTING.md](CONTRIBUTING.md) or open an issue on
47
+ > [mlaify/AttackMap](https://github.com/mlaify/AttackMap/issues) to say hello.
48
+ > Security reports are still welcome at [security@mlaify.io](mailto:security@mlaify.io).
49
+
50
+ C ecosystem analyzer for [AttackMap](https://github.com/mlaify/AttackMap).
51
+
52
+ C is more fragmented than language-specific ecosystems — there's no dominant web framework, and routing patterns vary widely. This analyzer captures what regex can reach reliably from common third-party libraries.
53
+
54
+ - **Web frameworks** — civetweb (`mg_set_request_handler` extracts routes), libmicrohttpd (`MHD_start_daemon` entrypoint), mongoose (`mg_http_listen` entrypoint + `mg_http_match_uri` pseudo-routes), libonion (`onion_url_add` routes)
55
+ - **HTTP clients (external calls)** — libcurl (`curl_easy_setopt(handle, CURLOPT_URL, "...")` URL string literals)
56
+ - **Databases** — sqlite3 (`sqlite3_open*`), libpq (`PQconnectdb*`, `PQsetdbLogin`), MySQL/MariaDB C client (`mysql_real_connect`, `mariadb_real_connect`), hiredis (`redisConnect*`), MongoDB C driver (`mongoc_client_new`)
57
+ - **Auth/crypto** — OpenSSL (TLS context, EVP cipher, RAND), mbedTLS (SSL/X.509), libsodium (`crypto_pwhash`, `crypto_secretbox`, `crypto_aead_*`), Argon2 reference impl (`argon2id_hash_*`), bcrypt-c, scrypt, JWT C libraries (`jwt_encode`, `jwt_decode`)
58
+ - **Secrets** — `getenv`, `secure_getenv`, `getenv_s` with secret-shaped names (`*SECRET*`, `*TOKEN*`, `*KEY*`, `*PASSWORD*`, `*PASS*`, `*PWD*`)
59
+ - **Service hints** — project name from `CMakeLists.txt` (`project(NAME ...)`)
60
+ - **Dependencies (SBOM)** — vcpkg, Conan and CMake manifests, so `--cve` reaches native dependencies; unpinned CMake downloads are reported as supply-chain issues (see [Dependencies](#dependencies))
61
+ - **Memory-safety and command-exec sinks** — unbounded copies, non-constant printf formats, `system`/`popen`/`exec*`, input-controlled `memcpy` lengths and allocation-size overflows, tied to request and input sources in the same function (see [Native sinks](#native-sinks))
62
+
63
+ All emissions populate AttackMap's Signal v2 fields (line numbers + evidence snippets + confidence) so downstream insights can cite `path/to/file.c:NN`.
64
+
65
+ ## Install
66
+
67
+ ```bash
68
+ uv tool install attackmap --with attackmap-analyzer-c \
69
+ --index mlaify=https://pkg.mlaify.io/pypi/simple/ --index-strategy first-index
70
+ # or from source:
71
+ pip install git+https://github.com/mlaify/attackmap-analyzer-c.git
72
+ ```
73
+
74
+ The analyzer is registered with AttackMap via the `attackmap.analyzers` entry-point group.
75
+
76
+ ## Usage with AttackMap
77
+
78
+ This analyzer is **experimental and opt-in** (`enabled_by_default=False`): installing it does not make it run on every scan. Select it explicitly:
79
+
80
+ ```bash
81
+ attackmap analyze /path/to/c/repo -m c
82
+ ```
83
+
84
+ ## Detection
85
+
86
+ `detect()` returns true when at least one `.c` file is present in the tree (a lone `.h`, such as an ObjC/Swift bridging header, doesn't count), in a single walk, ignoring `_deps/`, `third_party/`, `external/`, `.cache/` and AttackMap's shared skip list (`build/`, `out/`, `vendor/`, `node_modules/`, `.git/`, ...). Skip directories are matched only *inside* the repo, so a checkout under e.g. `/build/...` is still scanned. Files are walked with `attackmap.sdk.iter_repo_files`, which does not follow symlinks out of the repo, and read with `read_source`, which falls back to cp1252/latin-1 for legacy-encoded sources. A `CMakeLists.txt` alongside `.cpp` files (and no `.c` files) is **not** claimed by this analyzer — that's the C++ analyzer's territory.
87
+
88
+ ### `.h` ownership
89
+
90
+ `.h` ownership is decided per repo, by the same rule in both the C and C++ analyzers, so exactly one of them analyzes each header whichever of `-m c` / `-m cpp` is selected:
91
+
92
+ - `.h` belongs to **C++** if the repo has any C++ source or header (`.cpp`, `.cc`, `.cxx`, `.hpp`, `.hxx`, `.ipp`, `.tpp`) or a `CMakeLists.txt` that enables CXX (`project(... CXX ...)`, `enable_language(CXX)` or `CMAKE_CXX_STANDARD`). A bare `project(foo)` doesn't count.
93
+ - Otherwise `.h` belongs to **C**.
94
+ - Files under directories either plugin prunes (`build/`, `third_party/`, `Debug/`, `Release/`, ...) are never markers.
95
+
96
+ In a mixed repo, `.c` files go to C, and `.cpp`/`.hpp`/... plus `.h` go to C++. Running only one of the two analyzers on a mixed repo leaves the other's files unanalyzed. It never double-counts them.
97
+
98
+ ## Dependencies
99
+
100
+ `native_deps.py` emits `DependencyHint`s (mlaify/AttackMap#191). The module is shared verbatim with attackmap-analyzer-cpp. Core dedupes identical records when both analyzers run.
101
+
102
+ | Source | Ecosystem | Version | `dev` |
103
+ |---|---|---|---|
104
+ | `vcpkg.json` `dependencies` | `vcpkg` | `overrides` pin (`resolved=True`), else `>=` from `version>=`, else empty (the `builtin-baseline` decides; it's recorded in the evidence) | `"host": true` |
105
+ | `conanfile.txt` `[requires]` / `[tool_requires]` / `[build_requires]` / `[test_requires]` | `conan` | as written (`1.2.13`, `[>=1.80 <2.0]`) | tool/build/test sections |
106
+ | `conanfile.py` `requires = ...`, `self.requires("x/1.0")` and the tool/build/test forms (parsed with `ast`, never executed; comments and docstrings don't count) | `conan` | as written | tool/build/test |
107
+ | `conan.lock` (Conan 2 lists and Conan 1.x `graph_lock.nodes`) | `conan` | exact (`resolved=True`) | `build_requires`, build-context nodes |
108
+ | CMake `FetchContent_Declare` / `ExternalProject_Add` / `CPMAddPackage` | `cmake` | `GIT_TAG`, a CPM version, or a version in the archive URL | test/example manifests, test frameworks |
109
+ | CMake `find_package(Name [version] [EXACT])` | `cmake` | `>=version` / `==version`, ranges `1.2...<2.0` → `>=1.2,<2.0` | test/example manifests, test frameworks |
110
+
111
+ `cmake` is inventory-only in core: it has no OSV database, so `--cve` reports those dependencies as not CVE-checked. `conan` and `vcpkg` map to OSV ConanCenter and vcpkg. Build tools and CMake modules (`Threads`, `PkgConfig`, `Python3`, `Git`...) aren't dependencies.
112
+
113
+ **Unpinned downloads** are `SupplyChainIssue(kind="mutable_vcs_dependency")` records:
114
+
115
+ | Download | Severity |
116
+ |---|---|
117
+ | git download with no `GIT_TAG`, or a `GIT_TAG` that names a branch (`main`, `master`, `develop`...) | medium |
118
+ | any other tag or a short SHA | low |
119
+ | a full 40-hex commit SHA | not flagged |
120
+ | `URL` download without `URL_HASH`/`URL_MD5` | medium |
121
+
122
+ Values that are CMake variables (`${X}`) are never flagged. Comments, quoted strings and bracket arguments (`[[ ]]`) never contain commands. Malformed or deeply nested manifests are skipped.
123
+
124
+ ## Coverage notes
125
+
126
+ - **Marked experimental**: regex-based extraction in C has more false positives than language-with-strict-imports analyzers. Keep the confidence-tier model in mind when consuming output (0.6 keyword sweeps vs. 0.85+ canonical function-name hits).
127
+ - **Routes**: civetweb / mongoose / libonion all expose path strings explicitly in their routing API; libmicrohttpd does not (single-callback dispatch on `url`). For libmicrohttpd, only the entrypoint is captured — per-route URLs would need to be regexed out of `if (strcmp(url, "/x") == 0)` patterns inside the answer-callback.
128
+ - **HTTP method on routes**: the C web frameworks covered here don't statically declare HTTP methods at registration time (handlers branch on method internally), so all routes are emitted with method `ANY`.
129
+ - **OpenSSL EVP / RAND** signals are confidence 0.8 — they're broad indicators of crypto usage but not strong defensive signals on their own.
130
+ - **Authorization / Bearer / api_key keyword matches** are tier-0.6 (low confidence). They're useful as supporting evidence for an auth posture, not as load-bearing.
131
+ - **Hardcoded `#define JWT_SECRET "abc..."` macros** are not extracted — too noisy. `getenv("JWT_SECRET")` is the canonical pattern we rely on.
132
+
133
+ ## Native sinks
134
+
135
+ The analyzer emits function-local C weaknesses as `CodeWeakness` records (mlaify/AttackMap#189). Core turns them into findings, one per severity tier, with CWE/OWASP/ASVS ids.
136
+
137
+ | Kind (rule id) | Fires on | Not reported |
138
+ |---|---|---|
139
+ | `unbounded_copy` (CWE-120) | `gets`; `scanf`/`fscanf` `%s`/`%[` without a width; `strcpy`/`strcat`/`sprintf` `%s` whose source is traced to an input | a literal or untraced source; a source with an upper-bound check first (`strlen(s) < sizeof dst`, directly or through a length alias; `> 0` / `< 0` checks don't count); a sized destination (`malloc(strlen(s) + 1)`); `%.Ns`; a bounded read (`fgets`, `recv`, `%255s`) copied into an array at least as large |
140
+ | `format_string` (CWE-134) | a printf-family format (`printf`, `fprintf`, `sprintf`, `snprintf`, `syslog`, civetweb/mongoose `mg_printf`, `mg_http_reply`) that is not a constant | literals, `#define` and `static const` strings, literal ternaries, gettext `_()`, variadic and `va_list` wrappers forwarding their own `fmt`, untraced function results |
141
+ | `native_command_exec` (CWE-78) | `system`/`popen` with a non-constant command; `exec*` with an input-derived argument or a non-constant `sh -c` line | constant commands, `NULL`, an untraced `execv(path, args)` without a shell |
142
+ | `tainted_copy_length` (CWE-805) | `memcpy`/`memmove`/`strncpy`/`strncat` length traced to an input | lengths with an upper-bound check (`n > sizeof dst`, `ck_assert_int_lt(n, cap)`) or a clamp (`MIN`, `n > cap ? cap : n`, also inside the call) first, a destination allocated from the same length, a byte count returned by `recv`/`read` |
143
+ | `alloc_size_overflow` (CWE-680) | `malloc`/`realloc`/`alloca` of a product with an input-derived factor | `calloc`, sums, untraced factors, a factor with an upper-bound check first or a `SIZE_MAX`/`__builtin_mul_overflow` guard |
144
+
145
+ **Sources**, traced per function through assignments, out-parameters and copy functions:
146
+
147
+ - **Request input:** civetweb `mg_get_request_info`/`mg_get_header`/`mg_get_var`/`mg_read`, a `struct mg_request_info *` or `struct mg_http_message *`, mongoose `mg_http_get_var`/`mg_http_get_header`, and the `url`/`upload_data` parameters of a libmicrohttpd handler.
148
+ - **Network input:** `recv`/`recvfrom`/`SSL_read`/`BIO_read`/`mbedtls_ssl_read`, and `read` on a socket-named descriptor.
149
+ - **Local input:** stdin (`fgets(..., stdin)`, `scanf`), `argv`/`optarg` in a function that takes `argv`, `getenv`, and file reads.
150
+
151
+ Taint doesn't flow through calls to unknown functions (`gethostbyname(argv[1])`). A reassignment to a literal (`u = "default"`) clears it. A copy between two declared arrays where the destination is at least as large isn't reported.
152
+
153
+ **Severity and confidence:**
154
+
155
+ | Input traced to the sink | Severity / confidence |
156
+ |---|---|
157
+ | request or network | high / high |
158
+ | stdin, argv, env or file | medium / medium |
159
+ | none (only non-constant formats and commands are reported) | low / low |
160
+
161
+ Code under `examples/`, `demo/`, `samples/`, `contrib/` or `docs/` is capped at low. Test, fuzz and benchmark code (`test/`, `tests/`, `unittest/`, `fuzztest/`, `*_test.c`, ...) is skipped. `ATTACKMAP_INCLUDE_TESTS=1` scans it.
162
+
163
+ `native_sinks.py` is shared verbatim with attackmap-analyzer-cpp. It needs an `attackmap` core that exports `CodeWeakness` from `attackmap.sdk`. With an older core the analyzer still loads and emits no weaknesses.
164
+
165
+ ## License
166
+
167
+ MIT
@@ -0,0 +1,10 @@
1
+ attackmap_analyzer_c/__init__.py,sha256=G3ZOjgZiuQK_CDy8L7fcz7dbBgJffguB6_1Dkha8R0s,57
2
+ attackmap_analyzer_c/analyzer.py,sha256=d7o7hu5zTNf6nr-sWYe-0u-ya3mV1jJMZUOu5B1q9jA,19621
3
+ attackmap_analyzer_c/native_deps.py,sha256=EE-pcserTemXpfEnFoUa0OAYGV4EVtsWjwAXKr-iv-c,22933
4
+ attackmap_analyzer_c/native_sinks.py,sha256=LnbJL6sESAyD6zntYwhNUxtX9boIGzvriqxbnRvC5jo,72560
5
+ attackmap_analyzer_c-0.2.0.dist-info/licenses/LICENSE,sha256=vtPQVGUyxq359j0JmD3_eJaXyHmaHyjzaMOtaLwJc88,1097
6
+ attackmap_analyzer_c-0.2.0.dist-info/METADATA,sha256=EAy_VvhVndgWObzjHLqQ2UJUvdaBbmYYXgQosq3Z7nM,13341
7
+ attackmap_analyzer_c-0.2.0.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
8
+ attackmap_analyzer_c-0.2.0.dist-info/entry_points.txt,sha256=bbLuVViJv9O1QXdWbxvIkynOApW6BWyzb4gfjBR7K3E,57
9
+ attackmap_analyzer_c-0.2.0.dist-info/top_level.txt,sha256=nAhdEvU6t_VL0uOhBmYqTlFfTtz8JeCq8sAeMmBPmNY,21
10
+ attackmap_analyzer_c-0.2.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [attackmap.analyzers]
2
+ c = attackmap_analyzer_c:CAnalyzer
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matthew Davis and AttackMap Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ attackmap_analyzer_c