summaryrefslogtreecommitdiffstats
path: root/docs/writeups/angstromCTF_2022/uninspired.txt
diff options
context:
space:
mode:
Diffstat (limited to 'docs/writeups/angstromCTF_2022/uninspired.txt')
-rw-r--r--docs/writeups/angstromCTF_2022/uninspired.txt150
1 files changed, 150 insertions, 0 deletions
diff --git a/docs/writeups/angstromCTF_2022/uninspired.txt b/docs/writeups/angstromCTF_2022/uninspired.txt
new file mode 100644
index 0000000..cc1d6c6
--- /dev/null
+++ b/docs/writeups/angstromCTF_2022/uninspired.txt
@@ -0,0 +1,150 @@
+clam has no more inspiration :( maybe help him get some?
+
+Category: re (100 points)
+Chall author: aplet123
+Writeup author: malfurious
+
+
+
+Software RE
+-----------
+We are given an executable ELF binary, and RE reveals two functions of interest:
+main and print_flag.
+
+The main function will read a line of text from input and make various
+assertions about it, exiting if any fail. Eventually, on success, the user
+supplied string is passed to the print_flag function. print_flag uses the data
+to derive the flag string, then prints it of course.
+
+I didn't bother reversing the print_flag function, as main gives us a seemingly
+simple puzzle to solve in order to satify its requirements. Those requirements
+being:
+
+ - Input must be 10 characters
+ - Each character must be numeric ('0' - '9')
+ - The value of each character (digit) will increment a corresponding index
+ in an array ("count array")
+ - The final count array values must match the original input in sequence
+
+Therefore, we must supply a 10-digit number where each positional digit
+(starting from the left) is equal to the quantity of that positional value in
+the number overall. For example, consider this potential answer:
+
+ 9 0 0 0 0 0 0 0 0 0
+ ^ ^
+ zero position nine position
+
+The value of 9 in the zero position indicates that there must be a total of 9
+zeroes in the overall value, which there are. However, this is not a correct
+anwser, as there is a zero in the nine position while the actual number of nines
+is 1 (the one in the zero position).
+
+
+
+Numeric puzzle
+--------------
+Let's try to fixup the previous example to arrive at the correct solution. If
+we correct the nines position, there is now one fewer zeros, which would need
+its own correction, but there are other cascading issues as well.
+
+ 9 0 0 0 0 0 0 0 0 1 # wrong number of zeroes and ones
+ 8 0 0 0 0 0 0 0 0 1 # wrong number of eights, nines, ones
+ 8 1 0 0 0 0 0 0 1 0 # wrong number of zeroes and ones
+ ...
+
+Not 100% confident that there even was a solution, the team decided to try to
+rule out sets of potential solutions by reasoning our way to a contradiction
+from some given starting point (as you can see above, for the example of
+zero->nine).
+
+We decided to start by varying the value of zero, starting with zero set to
+nine. The reason for this being that maximizing the number of zeroes in the
+number should in theory minimize the additional values we need to fit in the
+remaining digits. If the nines position has a value of 1, for example, then
+that would imply that there must be nine of some other value elsewhere in the
+answer. Furthermore, a two in the nines position is impossible, since there
+aren't enough places to satify the requirements imposed by two floating nine
+digits.
+
+Using this process, we eliminated all solutions where the zero position is
+9, 8, or 7, however converged on a possible solution for zero->six.
+
+ 6 0 0 0 0 0 0 0 0 0 # wrong zeroes, sixes
+ 6 0 0 0 0 0 1 0 0 0 # wrong zeroes, ones
+ 6 1 0 0 0 0 1 0 0 0 # wrong zeroes, ones
+ 6 2 0 0 0 0 1 0 0 0 # wrong zeroes, ones, twos
+ 6 2 1 0 0 0 1 0 0 0 # all positions correct!
+
+It is unknown to the team whether there are other correct solutions. Since
+this string is used to derive the flag, it's likely that this is the only one.
+However, if the other solutions (if they exist) are somehow congruent under the
+logic of the print_flag function, then the puzzle should still hold.
+
+
+
+Solution
+--------
+> ./uninspired
+there's no more inspiration :(
+6210001000
+yay I'm inspired now, have a flag :)
+actf{ten_digit_numbers_are_very_inspiring}
+
+
+
+Decompiled main function (C/Ghidra)
+-----------------------------------
+undefined8 main(void)
+{
+ size_t str_len;
+ long idx;
+ undefined8 retval;
+ char *inp_ptr;
+ char user_input [10];
+ char user_input_end [6];
+ int buffer [4];
+ char c;
+
+ inp_ptr = user_input;
+ puts("there\'s no more inspiration :(");
+ fgets(user_input,0x10,stdin);
+ str_len = strcspn(user_input,"\n");
+ /* Read user input, fixup newline/null termination
+ Length of string must == 10 */
+ user_input[(int)str_len] = '\0';
+ if ((int)str_len == 10) {
+ /* zero buffer */
+ buffer = (undefined [16])0x0;
+ do {
+ /* foreach char in user_input */
+ c = *inp_ptr;
+ if (9 < (byte)(c - 0x30U)) {
+ /* characters must be numeric (0-9) */
+ puts("I don\'t like your inspiration :(");
+ return 1;
+ }
+ inp_ptr = inp_ptr + 1;
+ /* increment the selected position in 'buffer' */
+ buffer[(char)(c - 0x30U)] = buffer[(char)(c - 0x30U)] + 1;
+ } while (inp_ptr != user_input_end);
+ idx = 0;
+ do {
+ /* foreach char in user_input */
+ if (buffer[idx] != user_input[idx] + -0x30) {
+ /* buffer indicies must match input string values */
+ puts("that\'s not good inspiration :(");
+ return 1;
+ }
+ idx = idx + 1;
+ } while (idx != 10);
+ puts("yay I\'m inspired now, have a flag :)");
+ print_flag(user_input);
+ retval = 0;
+ }
+ else {
+ /* strlen != 10 */
+ puts("that\'s not very inspiring :(");
+ retval = 1;
+ }
+ return retval;
+}