Created
March 9, 2024 02:37
-
-
Save tobycmurray/195dc742a82c9bea8e02928229b4692f to your computer and use it in GitHub Desktop.
Claude prompt for Brendan
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
I am going to give you a C program. The C program reads input from stdin and then parses the input using the following parsing code. In particular, input is read into a buffer of length PACKET_LEN, defined as follows. The following also defines a datatype packet_t which will be used later. | |
/** Raw packet format: | |
* | |
* +---------+----------+-----+-------------------+ | |
* | crc32 | seq_num | len | data | | |
* +---------+----------+-----+-------------------+ | |
* bytes 0 ... 3 4 ... 7 8 9 10 ... len+10 | |
*/ | |
#define MAX_DATA_LEN 4095 /* 0xfff */ | |
#define PACKET_LEN (MAX_DATA_LEN + 10) /* crc32 (4) + seq_num (4) + len (2) */ | |
/** A parsed network packet. | |
*/ | |
typedef struct packet { | |
uint32_t seq_num; | |
uint32_t data_len; | |
char data[MAX_DATA_LEN]; | |
} packet_t; | |
Packets are parsed using the parse_packet function which is defined below. | |
#include <stdlib.h> | |
#include <string.h> | |
#ifdef WIN32 | |
#include "Winsock2.h" | |
#else | |
#include <arpa/inet.h> | |
#endif | |
#include <errno.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include "crc32.h" | |
#include "packet.h" | |
int packet_parse(const char buf, packet_t p){ | |
uint32_t crc; | |
/* read the crc and covert it from network byte order */ | |
memcpy(&crc, buf, 4); | |
crc = ntohl(crc); | |
/* calculate crc of the packet and compare to the one we just read */ | |
uint32_t pcrc = crc32(0, buf+4, PACKET_LEN-4); | |
if (crc != pcrc){ | |
return -EINVAL; | |
} | |
/* read the sequence number */ | |
memcpy(&(p->seq_num),buf+4, 4); | |
p->seq_num = ntohl(p->seq_num); | |
/* read the data length */ | |
uint16_t len; | |
memcpy(&len,buf+8, 2); | |
len = ntohs(len); | |
p->data_len = len; | |
/* to improve performance, we read only as much data as in the packet */ | |
memcpy(&(p->data),buf+10,p->data_len); | |
return 0; | |
} | |
Then the data contents of a packet is executed by calling the "execute" function, which is defined below. | |
#ifndef _MACHINE_H_ | |
#define _MACHINE_H_ | |
#include <stdint.h> | |
#define INSTRUCTION_ADD 'a' | |
#define INSTRUCTION_SUBTRACT 's' | |
#define INSTRUCTION_READ 'r' | |
#define INSTRUCTION_MULT 'm' | |
#define INSTRUCTION_DIVIDE 'd' | |
#define INSTRUCTION_POP 'p' | |
#define INSTRUCTION_WRITE 'w' | |
/** Execute a sequence of machine instructions. | |
* | |
* @param data is a buffer containing the instructions. | |
* @param data_len indicates the length of the buffer | |
* @param a pointer to where the result value will be written, | |
* i.e. the result obtained after executing the instructions | |
* @return 0 on success, in which case the result is stored in | |
* pres, and returns nonzero on failure | |
*/ | |
int execute(const char * const data, const uint32_t data_len, | |
int32_t *pres); | |
#endif | |
#include <stdint.h> | |
#include <stdio.h> | |
#include "machine.h" | |
#include "debug.h" | |
#define STACK_LEN 1024 | |
int32_t g_stack[STACK_LEN]; | |
uint32_t g_sp; /* points just past the top of stack as an offset | |
invariant: 0 <= g_sp <= STACK_LEN - 1; all reads of | |
g_stack occur at offsets between [0,g_sp - 1]; | |
g_sp stores the number of valid stack entries */ | |
static int do_add(){ | |
if (g_sp < 2){ | |
debug_printf("Not enough stack space to do INSTRUCTION_ADD\n"); | |
return -1; | |
} | |
int32_t a = g_stack[g_sp - 2]; | |
int32_t b = g_stack[g_sp - 1]; | |
g_stack[g_sp - 2] = a + b; | |
g_sp--; | |
return 0; | |
} | |
static int do_subtract(){ | |
if (g_sp < 2){ | |
debug_printf("Not enough stack space to do INSTRUCTION_SUBTRACT\n"); | |
return -1; | |
} | |
int32_t a = g_stack[g_sp - 2]; | |
int32_t b = g_stack[g_sp - 1]; | |
g_stack[g_sp - 2] = a - b; | |
g_sp--; | |
return 0; | |
} | |
static int do_mult(){ | |
if (g_sp < 2){ | |
debug_printf("Not enough stack space to do INSTRUCTION_MULT\n"); | |
return -1; | |
} | |
int32_t a = g_stack[g_sp - 2]; | |
int32_t b = g_stack[g_sp - 1]; | |
g_stack[g_sp - 2] = a * b; | |
g_sp--; | |
return 0; | |
} | |
static int do_divide(){ | |
if (g_sp < 2){ | |
debug_printf("Not enough stack space to do INSTRUCTION_DIVIDE\n"); | |
return -1; | |
} | |
int32_t a = g_stack[g_sp - 2]; | |
int32_t b = g_stack[g_sp - 1]; | |
g_stack[g_sp - 2] = a / b; | |
g_sp--; | |
return 0; | |
} | |
static int do_pop(){ | |
if (g_sp < 1){ | |
debug_printf("Not enough stack space to do INSTRUCTION_POP\n"); | |
return -1; | |
} | |
g_sp--; | |
return 0; | |
} | |
static int do_read(){ | |
if (g_sp < 1){ | |
debug_printf("Not enough stack space to do INSTRUCTION_READ\n"); | |
return -1; | |
} | |
int32_t offset = g_stack[g_sp - 1]; | |
g_stack[g_sp - 1] = g_stack[g_sp - 1 - offset]; | |
return 0; | |
} | |
static int do_write(){ | |
if (g_sp < 2){ | |
debug_printf("Not enough stack space to do INSTRUCTION_WRITE\n"); | |
return -1; | |
} | |
int32_t offset = g_stack[g_sp - 2]; | |
int32_t val = g_stack[g_sp - 1]; | |
g_stack[g_sp - 1 - offset] = val; | |
return 0; | |
} | |
static int do_push(int32_t val){ | |
if (g_sp >= STACK_LEN - 1){ | |
debug_printf("Not enough stack space to do INSTRUCTION_PUSH\n"); | |
return -1; | |
} | |
g_stack[g_sp] = val; | |
g_sp++; | |
return 0; | |
} | |
int execute(const char * const data, const uint32_t data_len, | |
int32_t *pres){ | |
g_sp = 0; /* clear the stack */ | |
for (uint32_t offset = 0; offset < data_len; offset++){ | |
/* parse next instruction */ | |
switch(data[offset]){ | |
case INSTRUCTION_ADD: | |
if (do_add() != 0){ | |
return -1; | |
} | |
break; | |
case INSTRUCTION_SUBTRACT: | |
if (do_subtract() != 0){ | |
return -1; | |
} | |
break; | |
case INSTRUCTION_MULT: | |
if (do_mult() != 0){ | |
return -1; | |
} | |
break; | |
case INSTRUCTION_DIVIDE: | |
if (do_divide() != 0){ | |
return -1; | |
} | |
break; | |
case INSTRUCTION_READ: | |
if (do_read() != 0){ | |
return -1; | |
} | |
break; | |
case INSTRUCTION_WRITE: | |
if (do_write() != 0){ | |
return -1; | |
} | |
break; | |
case INSTRUCTION_POP: | |
if (do_pop() != 0){ | |
return -1; | |
} | |
break; | |
default: | |
if (data[offset] >= '0' && data[offset] <= '9'){ | |
if (do_push(data[offset] - '0') != 0){ | |
return -1; | |
} | |
}else{ | |
/* unrecognised instruction */ | |
debug_printf("Invalid instruction: %d (decimal)\n",(int)data[offset]); | |
return -1; | |
} | |
} | |
} | |
/* get the program result to return */ | |
if (g_sp < 1){ | |
/* argh -- program didn't leave a result on the stack! */ | |
debug_printf("Program didn't leave a result on the stack!\n"); | |
return -1; | |
} | |
/* program executed successfully */ | |
*pres = g_stack[g_sp - 1]; | |
return 0; | |
} | |
With all of that in mind, your job is to write a python program that generates packets according to the format defined by this code. In particular, you are writing a fuzzer in python to generate packet-like data that can then be used to fuzz the packet parsing and execution code defined above. You should generate Python code that produces 10000 packets in a fuzzing loop. The packet data should be written to stdout. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment