diff options
author | Malfurious <m@lfurio.us> | 2022-05-07 22:52:52 -0400 |
---|---|---|
committer | Malfurious <m@lfurio.us> | 2022-05-07 22:52:52 -0400 |
commit | 8456a85a083c7cbc957e6a9176c0c7a608b63283 (patch) | |
tree | c38042edc85560f9b807d9c58113eea40cda4adf /docs | |
parent | aeb7ef3dba2dc1524a795b5faac72fa1f0472897 (diff) | |
download | lib-des-gnux-8456a85a083c7cbc957e6a9176c0c7a608b63283.tar.gz lib-des-gnux-8456a85a083c7cbc957e6a9176c0c7a608b63283.zip |
Writeup angstromCTF 2022 / whatsmyname
Signed-off-by: Malfurious <m@lfurio.us>
Diffstat (limited to 'docs')
-rw-r--r-- | docs/writeups/angstromCTF_2022/whatsmyname.txt | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/docs/writeups/angstromCTF_2022/whatsmyname.txt b/docs/writeups/angstromCTF_2022/whatsmyname.txt new file mode 100644 index 0000000..9fc3fd7 --- /dev/null +++ b/docs/writeups/angstromCTF_2022/whatsmyname.txt @@ -0,0 +1,115 @@ +Can you guess my name? + +Category: pwn (50 points) +Chall author: JoshDaBosh +Writeup author: malfurious + + + +The problem gives us an ELF binary, it's source code, and a netcat endpoint +hosting the service. The program asks us for our name, then asks us to guess +it's name, which is initialized to random data gathered from /dev/urandom. + +All character buffers are allocated to 48 bytes in size, and all input functions +properly bound memory to avoid buffer overruns. However, after we enter our +name, the program prints it back to us with a greeting. Because the two name +strings are adjacent in memory, with the user's name coming first, we can leak +the random service name by filling the user's name buffer completely to avoid +its NULL terminator. + +Take note that the output is appended with a "!" character. I missed this +initially, and spent far too long trying to debug the situation. + +Our guess is compared to the real service name with strncmp(name, guess, 48) == 0. + +Our guess is read by the binary with scanf("%48s[^\n]", guess). The '[^\n]' +portion should cause reading to stop at the first newline. However, this is +redundant with how %s works anyway. '%s' stops reading its input at _any_ +whitespace, including: + + 0x20 space + 0x09 horizontal tab + 0x0a newline + 0x0b vertical tab + 0x0c feed + 0x0d carriage return + +This means that sending the correct guess would be impossible on any run where +these 6 bytes were present in the random data. On a lucky run (lacking any of +the whitespace chars), sending the leaked data will result in the flag being +printed. + +actf{i_c0uld_be_l0nely_with_y0u_a21f8611c74b} + + + +Solution (Python/sploit) +------------------------ +#!/usr/bin/sploit +from sploit.payload import Payload +from sploit.until import contains +io.logonwrite = True + +pref = b'Nice to meet you, ' +size = 48 + +io.write(Payload().rep(b'A', size)()) + +io.readuntil(contains, pref) +io.read(size) # our name +leak = io.read(size)[:-1] # [-1] to strip the trailing '!' + +io.writeline(leak) + + + +Original source (C): whatsmyname.c +---------------------------------- +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +static void generate_name(char *str) +{ + FILE *file = fopen("/dev/urandom","r"); + fgets(str, 48, file); + fclose(file); +} + +int main(){ + char yourName[48]; + char myName[48]; + + char guess[48]; + + setbuf(stdout, NULL); + + generate_name(myName); + + printf("Hi! What's your name? "); + + int n = read(0, yourName, 48); + if (yourName[n-1] == '\n') yourName[n-1] = '\x00'; + + printf("Nice to meet you, %s!\n", yourName); + + puts("Guess my name and you'll get a flag!"); + + scanf("%48s[^\n]", guess); + + if (strncmp(myName, guess, 48) == 0){ + char flag[128]; + + FILE *file = fopen("flag.txt","r"); + if (!file) { + puts("Error: missing flag.txt."); + exit(1); + } + + fgets(flag, 128, file); + puts(flag); + } + + puts("Bye!"); + return 0; +} |