Skip to content

Instantly share code, notes, and snippets.

@tobycmurray
Created March 9, 2024 02:37
Show Gist options
  • Save tobycmurray/195dc742a82c9bea8e02928229b4692f to your computer and use it in GitHub Desktop.
Save tobycmurray/195dc742a82c9bea8e02928229b4692f to your computer and use it in GitHub Desktop.
Claude prompt for Brendan
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