aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorn0p <0x90@n0p.cc>2018-10-25 23:14:29 +0200
committern0p <0x90@n0p.cc>2018-10-25 23:14:29 +0200
commit6814897ce2de08180b6537fcccfb104827e2a131 (patch)
treecf07de03d5800f8dd6e1c265e6122f8fcb650655
downloadForgetfulCommander-6814897ce2de08180b6537fcccfb104827e2a131.tar.gz
ForgetfulCommander-6814897ce2de08180b6537fcccfb104827e2a131.zip
Init.
-rw-r--r--README.md31
-rw-r--r--entry.c233
-rw-r--r--forgetful_commander.c118
-rw-r--r--packer.py54
-rw-r--r--public/.gitkeep0
-rwxr-xr-xpublic/forgetful_commanderbin0 -> 25656 bytes
6 files changed, 436 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4365b85
--- /dev/null
+++ b/README.md
@@ -0,0 +1,31 @@
+Forgetful Commander
+===================
+
+# Author
+n0p
+
+# Description
+All typos in the flag are on purpose (brute-force prevention...)!
+
+
+# Challenge Text
+```
+And you lost a key again. This time it's the key to your missiles command
+station. However, the command station got a silent password override. Even
+though your memory isn't that good, you don't remember the password either,
+your technical skills are!. You've already dumped the binary, which checks the
+password. Now you just have to reverse it!
+```
+
+# Setup
+packer.py builds everything. Requires clang.
+
+# Solution
+Simple packer. Main program checks the argument against some XOR stuff.
+Depending on the trap flag, the argument is checked against the fail string.
+
+# Point Value
+dynamic
+
+# Flag
+flag{Just_type__Please__and_the_missles_will_be_launched.}
diff --git a/entry.c b/entry.c
new file mode 100644
index 0000000..f5bdf3d
--- /dev/null
+++ b/entry.c
@@ -0,0 +1,233 @@
+/*
+ * clang -s -m32 -nostdlib -nodefaultlibs -fPIC -Wl,-shared entry.c -oentry
+ */
+
+__attribute__((naked)) void entry() {
+ __asm__ volatile(
+ ".intel_syntax noprefix\n"
+ "push eax\n"
+ "pushad\n"
+ "pushfd\n"
+
+ "sub esp, 0x5000\n"
+
+ // get the pathname of the binary with readlink
+ "mov eax, 85\n"
+ // /proc/self/exe
+ "push 0x6578\n"
+ "push 0x652f666c\n"
+ "push 0x65732f63\n"
+ "push 0x6f72702f\n"
+ // pathname of the symlink
+ "mov ebx, esp\n"
+ // buf
+ "lea ecx, [esp + 0x4010]\n"
+ // bufsiz
+ "mov edx, 0xfff\n"
+ "int 0x80\n"
+
+ // cleanup arguments from stack
+ "add esp, 0x10\n"
+
+ "cmp eax, 0\n"
+ "jle fail\n"
+
+ // save the length of the pathname
+ "mov edi, eax\n"
+
+ // write newline at the end of the pathname
+ "lea ecx, [esp + 0x4000 + eax]\n"
+ "mov byte ptr [ecx], 0xa\n"
+
+ // inc saved length, to also compare the newline
+ "inc edi\n"
+
+ // open /proc/self/maps to get the base address of the binary
+ "mov eax, 5\n"
+ "push 0x737061\n"
+ "push 0x6d2f666c\n"
+ "push 0x65732f63\n"
+ "push 0x6f72702f\n"
+ "mov ebx, esp\n"
+ "xor ecx, ecx\n"
+ "int 0x80\n"
+
+ // cleanup arguments from stack
+ "add esp, 0x10\n"
+
+ "cmp eax, 0\n"
+ "jl fail\n"
+
+ // save the fd
+ "mov esi, eax\n"
+
+ // loop to get the program base
+ // read from /proc/self/maps
+ "read:"
+ "mov eax, 3\n"
+ "mov ebx, esi\n"
+ "mov ecx, esp\n"
+ "mov edx, 0x4000\n"
+ "int 0x80\n"
+
+ "cmp eax, 0\n"
+ "jle close\n"
+
+ // set maps iterator to 0
+ "xor ecx, ecx\n"
+ // set pathname iterator to 0
+ "xor edx, edx\n"
+ // ebp will be set to 0, if we got a match
+ "mov ebp, 1\n"
+
+ "find_pathname:\n"
+ "cmp ecx, eax\n"
+ "jge find_pathname_finished\n"
+
+ // char from the maps buffer
+ "movzx ebx, byte ptr [esp + ecx]\n"
+ // compare with char in the pathname buffer
+ // always inc maps iterator
+ "inc ecx\n"
+ "cmp byte ptr [esp + edx + 0x4000], bl\n"
+ "jnz find_pathname_no_match\n"
+ // inc pathname iterator
+ "inc edx\n"
+ // have we found the full pathname?
+ "cmp edx, edi\n"
+ "jnz find_pathname\n"
+ // jepp
+ "xor ebp, ebp\n"
+ "jmp find_pathname_finished\n"
+
+ "find_pathname_no_match:\n"
+ // reset pathname iterator
+ "xor edx, edx\n"
+ "jmp find_pathname\n"
+
+ "find_pathname_finished:\n"
+
+ // did we have a match?
+ "test ebp, ebp\n"
+ "jnz read\n"
+ // jepp
+ // search the beginning of the maps line
+ "find_beginning_of_line:"
+ "xor ebx, ebx\n"
+ "dec ecx\n"
+ // is the maps iterator non null?
+ "cmp ecx, 0\n"
+ "setg bl\n"
+ // is the char before the maps iterator not a '\n'
+ "cmp byte ptr [esp + ecx - 1], 0xa\n"
+ "setnz bh\n"
+ "test bl, bh\n"
+ "jnz find_beginning_of_line\n"
+
+ // convert the 8 hex digits to 4 bytes => the base address
+ "xor edx, edx\n"
+ "mov ebp, ecx\n"
+ "add ecx, 8\n"
+ "convert_base:"
+ "cmp ebp, ecx\n"
+ "jge close\n"
+ "rol edx, 4\n"
+
+ // check if it's a number
+ "xor ebx, ebx\n"
+ "cmp byte ptr [esp + ecx + ebp], 0x30\n"
+ "setge bl\n"
+ "cmp byte ptr [esp + ecx + ebp], 0x39\n"
+ "setle bh\n"
+ "sub byte ptr [esp + ecx + ebp], 0x30\n"
+ "xor dl, byte ptr [esp + ecx + ebp]\n"
+ "inc ebp\n"
+ "test bl, bh\n"
+ "jnz convert_base\n"
+ // wasn't a number, revert stuff
+ "dec ebp\n"
+ "xor dl, byte ptr [esp + ecx + ebp]\n"
+ "add byte ptr [esp + ecx + ebp], 0x30\n"
+ // check if it's a lowercase hex letter
+ "xor ebx, ebx\n"
+ "cmp byte ptr [esp + ecx + ebp], 0x61\n"
+ "setge bl\n"
+ "cmp byte ptr [esp + ecx + ebp], 0x7a\n"
+ "setle bh\n"
+ "sub byte ptr [esp + ecx + ebp], 0x57\n"
+ "xor dl, byte ptr [esp + ecx + ebp]\n"
+ "inc ebp\n"
+ "test bl, bh\n"
+ "jnz convert_base\n"
+ // wasn't a lowercase hex letter, revert stuff
+ "dec ebp\n"
+ "xor dl, byte ptr [esp + ecx + ebp]\n"
+ "add byte ptr [esp + ecx + ebp], 0x61\n"
+ // check if it's an uppercase hex letter
+ "xor ebx, ebx\n"
+ "cmp byte ptr [esp + ecx + ebp], 0x41\n"
+ "setge bl\n"
+ "cmp byte ptr [esp + ecx + ebp], 0x5a\n"
+ "setle bh\n"
+ "sub byte ptr [esp + ecx + ebp], 0x37\n"
+ "xor dl, byte ptr [esp + ecx + ebp]\n"
+ "inc ebp\n"
+ "test bl, bh\n"
+ "jnz convert_base\n"
+ // wasn't an uppercase hex letter, failed to convert
+ "xor edx, edx\n"
+ "jmp close\n"
+
+ "jmp read\n"
+
+ "close:\n"
+ // close the fd
+ "mov eax, 6\n"
+ "mov ebx, esi\n"
+ "int 0x80\n"
+
+ // if the base hasn't been found quit
+ "test edx, edx\n"
+ "jz fail\n"
+
+ // set the oep as return
+ "add edx, 0x2050\n"
+ "mov dword ptr [esp + 0x5024], edx\n"
+ "sub edx, 0x50\n"
+
+ "mov ebp, eax\n"
+ "inc eax\n"
+ "inc eax\n"
+
+ "dec_outer_loop:\n"
+ "mov esi, 0x466c7578\n"
+ "xor ebx, ebx\n"
+ "cmp eax, ebp\n"
+ "jz dec_outer_loop_finished\n"
+
+ "mov ecx, 0x400\n"
+
+ "dec_inner_loop:\n"
+ "xor dword ptr [edx], ebx\n"
+ "xor dword ptr [edx], esi\n"
+ "ror esi, 8\n"
+ "mov ebx, dword ptr [edx]\n"
+ "add edx, 4\n"
+ "loop dec_inner_loop\n"
+
+ "dec eax\n"
+ "jmp dec_outer_loop\n"
+
+ "dec_outer_loop_finished:\n"
+
+ "add esp, 0x5000\n"
+ "popfd\n"
+ "popad\n"
+ "ret\n"
+
+ "fail:\n"
+ // exit the program gracefully
+ "mov eax, 1\n"
+ "xor ebx, ebx\n"
+ "int 0x80");
+}
diff --git a/forgetful_commander.c b/forgetful_commander.c
new file mode 100644
index 0000000..e538503
--- /dev/null
+++ b/forgetful_commander.c
@@ -0,0 +1,118 @@
+/*
+ * clang -s -m32 -pie forgetful_commander.c -oforgetful_commander_unpacked
+ */
+
+#include <string.h>
+
+const char data[] = "\x4f\xb0\xab\x36\x1e\xb9\x59\x88\xa1\xe1\xf4\xef\x2f\x97"
+ "\x77\x83\x34\xa8\xe1\x70\x6f\x2c\xbe\x06\xc6\xb7\xd2\xa3"
+ "\x24\x1e\xf1\x78\xed\xdc\x4f\x9e\xa0\xb2\xf6\x10\xdf\xbe"
+ "\x33\xb4\x88\xf8\xeb\xe2\xc0\x1c\xed\x07\x0e\xe5\xb4\xde"
+ "\x07\xee\x6a\x5c\xb3\xe8\x37\x71\x8b\xf5\x6e\xf3\x33\xf0"
+ "\x86\x50\xf5\x15\x8b\xed\x84\x77\x1e\x7b\x02\xe0\x56\x5e"
+ "\x93\xba\x1a\x8c\x0f\xd2\xeb\x16\xb3\x83\x98\xfc\xd2\x81"
+ "\x87\xf3\xa0\x27\x5a\x4f\xe2\x38\x6f\xa0\x6c\xdd\x1d\x11"
+ "\x65\x69\xde\xe7\x27\x89\xe2\x95\xb6\x48\x39\x00\xf1\x8b"
+ "\x60\x1f\xfd\x8b\x73\x8f\x7d\x68\xd7\x3a\x19\x6d\x3a\x02"
+ "\x8a\xc5\x90\x25\x8c\x27\x77\x74\x8c\xeb\x90\x1f\x7a\x25"
+ "\xf8\x6a\x61\x8c\x4c\xa6\x56\x0c\xfb\x4a\x65\xb4\xeb\x12"
+ "\x9d\x27\xb7\x42\x8d\x9d\xec\x76\x96\x8e\xca\x86\x0f\xb2"
+ "\xc4\x14\x9f\x05\xba\xa7\x43\x7a\x7f\x2b\xf9\x33\x36\x1e"
+ "\xcf\x55\x63\x8a\xe2\x3b\x68\x02\x3f\x18\xd9\xbb\x6d\x8d"
+ "\xe5\x4b\xbe\x8f\x6c\x58\x1d\xfe\x17\x62\xb8\xa6\x8f\xb0"
+ "\xf7\x2b\x14\xc0\xb6\xf0\x2c\x25\x02\x2f\x2b\x79\xd8\x41"
+ "\x66\x52\x7b\xc6\x88\x72\x47\x31\x0c\x37\x6e\x34\xe2\x2c"
+ "\xd4\x95\x43\x68\x09\x26\xbb\x93\x24\x3f\x5a\x66\x41\xc4"
+ "\xdc\xaf\xf4\xa2\xa0\x00\x55\x23\x1a\x09\x3c\x51\xa0\xfa"
+ "\xa6\xda\x4c\x29\x5a\x6d\x24\x94\x98\x60\xcb\x19\x4e\xe7"
+ "\x32\x7c\x98\x4c\x6e\x0a\x21\xcd\x8e\xa8\x73\x73\x15\x0b"
+ "\x55\xad\xb9\x22\x53\x23\x33\x3f\x28\xb5\x50\x64\x56\xc8"
+ "\x5d\x4e\x89\x2a\x5f\xe5\x94\xe6\x7b\xc4\x15\x1b\x42\x70"
+ "\x4b\x19\x0f\xec\x0d\x4f\x9a\x1f\x6d\x3f\x10\x1e\x03\x98"
+ "\x8b\x1b\x56\x22\xfd\x77\x0a\x01\x5e\xa6\x36\xd9\xde\x22"
+ "\x03\xed\xba\xab\xb5\xcf\x1c\x72\x04\x41\x92\x34\xa4\xeb"
+ "\xde\xa9\x41\x1d\x20\xb0\xd6\x52\x19\xec\xb4\x08\x10\xc7"
+ "\x3f\xa2\x1e\x1a\x61\x38\x0b\x8b\x02\x46\x1c\x4e\x53\x4e"
+ "\xa0\x73\xb7\x7c\x2c\x2e\x0c\xd9\xfd\xd6\x3b\x34\xbb\xf7"
+ "\xea\xe3\xc9\x1b\x26\x8a\x33\x8f\xaf\xd7\x7a\xad\x72\x19"
+ "\xf1\x92\x79\xdf\xa9\x9d\x9c\x19\xc6\x82\x9a\xfd\x64\x7a"
+ "\xfe\xdb\x56\xc4\x54\x88\xb9\x26\x4c\xd7\xb6\xd6\xc2\x4b"
+ "\x71\x91\x8e\xfa\xb1\xdd\xfc\x9b\x29\xdc\xa8\x4e\xe7\x75"
+ "\x31\xf0\x99\x72\x3c\x4f\x7a\x42\x9d\x9d\x60\x9e\xf9\xfa"
+ "\xd6\xbb\x71\xfd\x19\x4b\x5d\x8d\x7c\x9f\x62\xd3\x14\x11"
+ "\xee\x5d\x7a\x5d\x97\xae\x96\xfb\x79\xc5\x7c\xf6\xc0\x55"
+ "\xbd\x7a\xc7\x81\x48\x64\xe7\x3b\xcf\x27\xd6\xcc\xd2\x39"
+ "\xce\x30\xce\x9d\xf9\xfa\x4a\x9e\x0b\x28\xf3\x39\x6b\xcf"
+ "\xa1\x3a\x4a\xf5\x70\x0e\x54\x66\x8b\x7d\x56\x68\x6e\x7e"
+ "\xc5\xde\x6f\x9c\xd0\xc8\x83\x90\x4d\xb1\xbc\x90\xef\x85"
+ "\xd8\xc3\x76\x3c\x72\x9f\x74\x75\x72\xd5\xbd\x33\xd7\xb5"
+ "\x8d\xe7\x59\xa2\x7a\x20\x81\xce\x47\x85\x56\x15\xc2\xb3"
+ "\x5b\x30\x6c\xf7\x45\xf1\x0e\xb3\x11\x8f\x20\x76\x7a\xd8"
+ "\xdd\x47\x8f\xe2\x43\x8c\xf0\x97\x33\x91\xce\xb1\xf5\x3f"
+ "\x8d\x42\x06\xa6\xd7\x77\xc3\xc3\xe2\xd2\x20\x50\x71\xbc"
+ "\x9c\x6f\xac\xad\x2f\x99\xb0\xf4\xb3\xf7\x73\x68\xbc\xf2"
+ "\x35\x33\x37\x9c\x56\x46\x81\xf9\xd2\xf2\x25\x1b\xdb\xe6"
+ "\x85\xfc\x30\x2d\xd1\x94\x6a\x2d\x13\x1a\xfa\xc5\x95\xcc"
+ "\x0c\xd2\xc1\xc9\x88\xf9\x66\x65\x18\x50\x52\x3a\x3b\x89"
+ "\xda\xed\xc0\x92\x22\x60\x75\x21\xa5\x7e\x8d\xe0\x84\x5e"
+ "\xb6\x0d\xc3\xbe\xfd\x31\xcf\x8b\x40\xf6\x97\xa1\x80\xaa"
+ "\xb7\x46\x38\xc7\x08\x81\xc3\x79\xbc\x25\xb3\xc8\x94\x66"
+ "\x54\x0d\xd0\x3b\x83\x8c\xd8\x28\x4e\x75\xcf\x6c\x29\xce"
+ "\x25\xd2\xbb\xaa\xab\xd7\x89\x49\x7d\xaf\xad\x8e\x1a\x73"
+ "\xe5\x61\x2e\x44\x3d\x6f\x38\xd9\x98\x76\xa5\x16\xc8\xbb"
+ "\x91\x46\x18\x0c\x86\x6a\x62\x7d\xfb\xea\x2f\xad\x3d\x4d"
+ "\x4d\x30\x37\x3a\x97\x13\x49\x36\xfe\x15\xfd\x2b\xdc\x3d"
+ "\x08\x8c\xb1\x25\x4a\xda\x0f\xbd\x41\xcf\xdc\xe7\xaf\x9a"
+ "\x4c\x59\x68\xcd\x03\x38\x6c\xf1\x2d\xb2\x1b\x95\x1b\x75"
+ "\x75\xae\x0e\x0e\xcf\xed\x52\x3e\x2d\x53\x79\xbb\x17\xa5"
+ "\x74\xb6\x9b\x0e\xa6\x75\xe4\x8b\xea\x6e\x91\xe6\xf3\x03"
+ "\xa5\x56\xe4\x4a\x18\x5d\x75\x5d\x7f\x7b\x4e\xea\xd2\x8f"
+ "\x39\x1d\x68\xe6\x52\x64\xce\x14\x9d\x35\x84\x64\xdc\x4e"
+ "\xb0\x10\x59\x1d\xc1\x3d\x60\xe7\xd3\x3e\xfe\x21\xcc\x95"
+ "\xfa\xf9\x1e\x74\xf8\x3c\x44\x2f\xef\x1f\x80\xac\xea\xdc"
+ "\x30\xfd\x21\x05\xa7\x35\xf1\x97\xfa\x4a\x39\x78\x38\x5f"
+ "\xef\xdc\x48\xfb\x76\xfc\x42\x46\xce\xfc\x29\x3f\xf2\xe6"
+ "\x51\x01\xb2\xb7\x32\x9c\x73\xc4\x7e\xa7\x14\x06\x97\xe9"
+ "\x00\x01\x87\x57\x6f\x3b\x88\x09\xac\xbd\x21\xbe\x57\x9a"
+ "\xcf\x10\xfd\x81\x2c\x10\xbd\x46\x75\xae\x41\xaf\xa6\xe4"
+ "\x78\x84\xc0\xaa\x74\x4b";
+
+const char xor[] = "\xdf\x98\xe2\x08\xcc\xbb\xeb\xac\x8c\xb2\xaa\xca\x85\xe3"
+ "\xb2\x5d\xea\x87\x99\xc1\x4b\x78\xb8\xe9\xea\x1d\x5e\xd5"
+ "\x53\xf8\x0f\x09\xd9\xde\x05\x7c\x69\x1a\x6d\xbd\x6f\x8c"
+ "\x34\xd4\x74\x4e\x1c\x24\x5d\x83\x1d\x4a\xa7\xc8\x6c\xc2"
+ "\x43\xb6";
+
+int main(int argc, char *argv[]) {
+ if (argc != 2) {
+ return 1;
+ }
+
+ int matchCounter = 0, offset = 5, key = 5;
+
+ for (int i = 0; i < strlen(argv[1]); i++) {
+ char tmp = argv[1][i];
+
+ __asm__ volatile(
+ "pushfd\n"
+ "pop %%edx\n"
+ "mov %%edx, %%ecx\n"
+ "and $0x100, %%ecx\n"
+ "xor %%ecx, %%edx\n"
+ "ror $2, %%ecx\n"
+ "xor %%ecx, %%edx\n"
+ "push %%edx\n"
+ "mov %1, %%edx\n"
+ "popfd\n"
+ "cmovz %%ecx, %%edx\n"
+ "mov %%edx, %0\n"
+ : "=r"(offset)
+ : "r"(offset));
+
+ if (tmp == (xor[i] ^ data[offset + i * key])) matchCounter++;
+ }
+
+ if (matchCounter == 58) return 0;
+
+ return 1;
+}
diff --git a/packer.py b/packer.py
new file mode 100644
index 0000000..b74a5ac
--- /dev/null
+++ b/packer.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python2
+
+import lief
+import os
+import subprocess
+
+subprocess.call(["clang", "-s", "-m32", "-nostdlib", "-nodefaultlibs", "-fPIC", "-Wl,-shared", "entry.c", "-oentry_tmp"])
+subprocess.call(["clang", "-s", "-m32", "-pie", "forgetful_commander.c", "-oforgetful_commander_tmp"])
+
+entry = lief.parse("entry_tmp")
+forgetful_commander = lief.parse("forgetful_commander_tmp")
+
+segment_added = forgetful_commander.add(entry.segments[1])
+
+forgetful_commander.header.entrypoint = segment_added.physical_address
+
+# Encrypt exec segment
+content = forgetful_commander.segments[3].content
+
+clr = [0, 0, 0, 0]
+flux = [0x78, 0x75, 0x6c, 0x46]
+for i in xrange(0, len(content), 4):
+ tmp = content[i:i+4]
+ content[i] ^= flux[0] ^ clr[0]
+ content[i+1] ^= flux[1] ^ clr[1]
+ content[i+2] ^= flux[2] ^ clr[2]
+ content[i+3] ^= flux[3] ^ clr[3]
+ flux.append(flux.pop(0))
+ clr = tmp
+
+forgetful_commander.segments[3].content = content
+forgetful_commander.segments[3].add(lief.ELF.SEGMENT_FLAGS.W)
+
+# Encrypt ro segment
+content = forgetful_commander.segments[4].content
+
+clr = [0, 0, 0, 0]
+flux = [0x78, 0x75, 0x6c, 0x46]
+for i in xrange(0, len(content), 4):
+ tmp = content[i:i+4]
+ content[i] ^= flux[0] ^ clr[0]
+ content[i+1] ^= flux[1] ^ clr[1]
+ content[i+2] ^= flux[2] ^ clr[2]
+ content[i+3] ^= flux[3] ^ clr[3]
+ flux.append(flux.pop(0))
+ clr = tmp
+
+forgetful_commander.segments[4].content = content
+forgetful_commander.segments[4].add(lief.ELF.SEGMENT_FLAGS.W)
+
+forgetful_commander.write("public/forgetful_commander")
+
+os.remove("entry_tmp")
+os.remove("forgetful_commander_tmp")
diff --git a/public/.gitkeep b/public/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/public/.gitkeep
diff --git a/public/forgetful_commander b/public/forgetful_commander
new file mode 100755
index 0000000..339d27c
--- /dev/null
+++ b/public/forgetful_commander
Binary files differ