Skip to content

Instantly share code, notes, and snippets.

@Aqcurate
Created August 9, 2022 00:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aqcurate/e1f9db9daf35a52e313d1cb7ead8d225 to your computer and use it in GitHub Desktop.
Save Aqcurate/e1f9db9daf35a52e313d1cb7ead8d225 to your computer and use it in GitHub Desktop.
archival exploit

Archival

The program (source given), unpacks a custom archive file. If we run strings on the archive file, however, it appears that not all the files get unpacked, specifically a hidden "flag.png" file.

000db100: 3db9 bff7 28f0 e20b bb76 0a00 00e7 1f66  =...(....v.....f
000db110: 6c61 672e 706e 6700 4f6e 58a9 15ea 15fd  lag.png.OnX.....
000db120: 1fe7 12e7 57ae 4da3 1fe7 90e6 1fe7 01e7  ....W.M.........

A packed file starts with the metadata [bsz (4)][k1 (1)][k2 (1)][name]. So if the offset to flag.png name is 0xdb10f, then 0xdb10f-6 is the start of the block.

We can reuse the program to force it to unpack this block.

fblk_t blk2;
parse_fblk(buff, 0x000db10f+0x1000, 0x000db10f-6, &blk2);
FILE *fp = fopen(blk2.name, "wb");
if (fwrite(blk2.data, 1, blk2.length, fp) != (size_t) blk2.length) {
    puts("Error writing output file");
    free(buff);
    return 1;
}  

Compiling and running it shows that this works.

$ gcc extract.c -o extract; ./extract arc out; ls -al out/flag.png
paint.png
aaaa.png
sentence.png
yeehaw.png
flag.png
-rw-rw-r-- 1 andrew andrew 2663 Aug  8 17:21 out/flag.png

Flag: l05t_buT_n0t_f0rGotT3n_18a9b735

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
typedef struct fblk_t {
char *name;
char *data;
int length;
} fblk_t;
#define INLINE static inline __attribute__((always_inline))
INLINE char *read_file(char *fname, long *sz) {
FILE *fp = fopen(fname, "rb");
if (!fp) return NULL;
fseek(fp, 0L, SEEK_END);
*sz = ftell(fp);
rewind(fp);
char *buff = malloc(*sz);
if (!buff) {
fclose(fp);
return NULL;
}
if (fread(buff, 1, *sz, fp) != (size_t) *sz) {
fclose(fp);
return NULL;
}
fclose(fp);
return buff;
}
INLINE int parse_fblk(char *buff, long sz, int off, fblk_t *out) {
if (off >= sz) return -1;
char *blk = buff + off;
int bsz = *(int *) blk;
if (bsz + off > sz) return -1;
char k1 = blk[4], k2 = blk[5];
char *name = blk + 6;
int namelen = (int) strnlen(name, bsz-6);
if (namelen >= bsz-6) return -1;
for (int i = namelen + 7; i < bsz; i += 2) {
if (i+1 < bsz) {
char tmp = blk[i];
blk[i] = blk[i+1] ^ k1;
blk[i+1] = tmp ^ k2;
} else {
blk[i] ^= k1;
}
}
out->name = name;
printf("%s\n", name);
out->data = name + namelen + 1;
out->length = bsz - namelen - 7;
return 0;
}
int main(int argc, char **argv) {
if (argc < 3) {
printf("Usage: %s <archive> <output directory>\n", argv[0]);
return 1;
}
long sz = 0;
char *buff = read_file(argv[1], &sz);
if (!buff) {
puts("Error reading file");
return 1;
}
if (sz < 4) {
puts("Error parsing file");
free(buff);
return 1;
}
int filecnt = (*(int *) buff);
int *fileoffs = ((int *) buff) + 1;
if (filecnt * 4 + 4 > sz) {
puts("Error parsing file");
free(buff);
return 1;
}
if (chdir(argv[2])) {
puts("Error changing directory");
free(buff);
return 1;
}
for (int i = 0; i < filecnt; i++) {
fblk_t blk;
if (parse_fblk(buff, sz, fileoffs[i], &blk)) {
puts("Error parsing file");
free(buff);
return 1;
}
FILE *fp = fopen(blk.name, "wb");
if (!fp) {
puts("Error opening output file");
free(buff);
return 1;
}
if (fwrite(blk.data, 1, blk.length, fp) != (size_t) blk.length) {
puts("Error writing output file");
free(buff);
return 1;
}
fclose(fp);
}
fblk_t blk2;
parse_fblk(buff, 0x000db10f+0x1000, 0x000db10f-6, &blk2);
FILE *fp = fopen(blk2.name, "wb");
if (fwrite(blk2.data, 1, blk2.length, fp) != (size_t) blk2.length) {
puts("Error writing output file");
free(buff);
return 1;
}
free(buff);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment