etc.git


etc

~ scripts and random things
git clone https://github.com/djnnvx/etc.git
log | files | refs | archive

fuzz_auth_header.c (4196B)

      1 /*
      2  * AFL++ / LibFuzzer harness — TTYD HTTP Authentication Header
      3  *
      4  * Target: the real check_auth() function from ttyd's http.c
      5  * Technique: #include the source file directly so static functions are
      6  *            accessible (standard OSS-Fuzz approach).
      7  *
      8  * Input format: [mode:1][credential_len:2 BE][credential][auth_header_value]
      9  *   mode 0 — no auth required
     10  *   mode 1 — Basic auth  (credential = expected base64 value)
     11  *   mode 2 — custom header auth (X-Auth-User)
     12  *
     13  * Build (handled by build_fuzzers.sh):
     14  *   afl-clang-fast -fsanitize=address,undefined -g -O1
     15  *     -I fuzz-include -I ttyd-src/src
     16  *     fuzz_auth_header.c
     17  *     ttyd-obj/{http,protocol,utils,fuzz_lws_mock,mock_server_globals,mock_pty_stubs}.o
     18  *     -ljson-c -o fuzz_auth_header
     19  */
     20 
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <stdint.h>
     25 #include <stdbool.h>
     26 
     27 /* Mock lws control state — must come before including the real ttyd source */
     28 #include "fuzz_lws_mock.h"
     29 
     30 /* Pull in the real ttyd structs (server.h included transitively via http.c) */
     31 /* fuzz-include/libwebsockets.h and fuzz-include/uv.h shadow the real ones   */
     32 #include "ttyd-src/src/http.c"   /* gives us static check_auth() */
     33 
     34 /* Provided by mock_server_globals.c */
     35 extern struct server  _fuzz_server;
     36 extern void           fuzz_server_reset(void);
     37 
     38 /* ── fuzz target ─────────────────────────────────────────────────────────── */
     39 
     40 int fuzz_target(const uint8_t *data, size_t size) {
     41     if (size < 3) return 0;
     42 
     43     /* Parse structured input */
     44     uint8_t  mode     = data[0] % 3;
     45     uint16_t cred_len = (uint16_t)((data[1] << 8) | data[2]);
     46     if ((size_t)cred_len > size - 3) cred_len = (uint16_t)(size - 3);
     47 
     48     /* Reset fuzzer-controlled lws state and the server global */
     49     fuzz_lws_reset();
     50     fuzz_server_reset();
     51 
     52     /* Set up the credential the server expects */
     53     static char cred_buf[65536];
     54     if (mode == 1 && cred_len > 0) {
     55         /* Basic auth: credential bytes become the expected base64 value */
     56         memcpy(cred_buf, data + 3, cred_len);
     57         cred_buf[cred_len] = '\0';
     58         _fuzz_server.credential  = cred_buf;
     59         _fuzz_server.auth_header = NULL;
     60     } else if (mode == 2) {
     61         /* Custom header auth */
     62         _fuzz_server.credential  = NULL;
     63         _fuzz_server.auth_header = (char *)"X-Auth-User";
     64     }
     65     /* mode 0: no auth, both remain NULL */
     66 
     67     /* Remaining bytes are the inbound Authorization header value that
     68      * lws_hdr_copy() will return via the mock */
     69     const uint8_t *auth_data  = data + 3 + cred_len;
     70     size_t         auth_len   = size - 3 - cred_len;
     71     fuzz_lws_set_auth((const char *)auth_data, (int)auth_len);
     72 
     73     /* For custom-header mode, same bytes are treated as the custom header */
     74     if (mode == 2)
     75         fuzz_lws_set_custom((const char *)auth_data, (int)auth_len);
     76 
     77     /* Call the REAL check_auth() from http.c */
     78     struct lws      mock_wsi = {0};
     79     struct pss_http pss      = {0};
     80     (void)check_auth(&mock_wsi, &pss);
     81 
     82     return 0;
     83 }
     84 
     85 /* ── AFL++ persistent mode ───────────────────────────────────────────────── */
     86 #ifdef __AFL_FUZZ_TESTCASE_LEN
     87 __AFL_FUZZ_INIT();
     88 int main(void) {
     89 #ifdef __AFL_HAVE_MANUAL_CONTROL
     90     __AFL_INIT();
     91 #endif
     92     unsigned char *buf = __AFL_FUZZ_TESTCASE_BUF;
     93     while (__AFL_LOOP(10000)) {
     94         fuzz_target(buf, __AFL_FUZZ_TESTCASE_LEN);
     95     }
     96     return 0;
     97 }
     98 
     99 #else
    100 /* LibFuzzer */
    101 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    102     return fuzz_target(data, size);
    103 }
    104 
    105 #ifndef LIBFUZZER
    106 /* Standalone file-based testing */
    107 int main(int argc, char **argv) {
    108     if (argc != 2) { fprintf(stderr, "Usage: %s <input_file>\n", argv[0]); return 1; }
    109     FILE *f = fopen(argv[1], "rb");
    110     if (!f) { perror("fopen"); return 1; }
    111     fseek(f, 0, SEEK_END); long sz = ftell(f); rewind(f);
    112     uint8_t *buf = malloc(sz);
    113     fread(buf, 1, sz, f); fclose(f);
    114     fuzz_target(buf, sz);
    115     free(buf);
    116     return 0;
    117 }
    118 #endif
    119 #endif