Questions about this topic? Sign up to ask in the talk tab.


From NetSec
Jump to: navigation, search
   06:01 < rorschach> ok, you guys ready for ptrace?
   06:01 <~hatter> I am
   06:01 < rorschach> good enough for me :3
   06:02 < rorschach> does anyone here not know what ptrace is?
   06:02 < Dwaan> me
   06:02 < Dwaan> lol
   06:02 < rorschach> ok
   06:02 <+Atlas> ^
   06:02 < rorschach> ptrace is the linux debugging API
   06:03 < rorschach> it provides a way for one process to trace another
   06:03 < jessicaparker> TOTALLY not exploitable.
   06:03 < jessicaparker> That's why we're discussing it.
   06:03 <~hatter> lol
   06:03 < rorschach> ;p
   06:03 < rorschach> anyway
   06:03 <%foo>
   06:03   hatter sets +o rorschach
   06:03   rorschach sets +m
   06:03   rorschach sets -m
   06:04 <@rorschach> shhh
   06:05 <@rorschach> ok, so a traced process can have it's memory read, it's memory can be written to freely, signals can be caught, the registers can be read and written to and execution can be stopped and continued.
   06:05 <@rorschach> essentially, as long as the process is being traced it is under complete control of the tracer
   06:05 <@rorschach> there are two ways to trace a process
   06:06 <@rorschach> by creating it or attaching to it
   06:06 <@rorschach> ptrace is essentially one function (publiclly at least)
   06:07 <@rorschach> the prototype (from the man pages):
   06:07 <@rorschach>        long ptrace(enum __ptrace_request request, pid_t pid,
   06:07 <@rorschach>                    void *addr, void *data);
   06:08 <@rorschach> __ptrace_request is the action that is reuested
   06:08 < alphis> sites down =[
   06:08 <~hatter> no its not alphis
   06:08 <~hatter>
   06:08 < alphis> it changed again?
   06:08 <~hatter>
   06:08 <~hatter> uh
   06:08 < alphis> ;/
   06:08 <~hatter> its been in the topic for a month
   06:08 <~hatter> at least
   06:08 <~hatter> :|
   06:08 <~hatter> lol
   06:08 < jessicaparker> irc server is changed too to .net
   06:08 < alphis> im using
   06:08 < alphis> which used to be new
   06:09 <~hatter> That's up
   06:09 <~hatter> from here
   06:09 <~hatter> Idk why that'd be down
   06:09 <@rorschach> ....
   06:09 < alphis> oh its just me?
   06:09 <~hatter> Continue rorschach
   06:09 <~hatter> sorry
   06:09 <~hatter> yes alphis just you
   06:09 <@rorschach> alphis: shh. wrong chan.
   06:09 <~hatter> my bad rorschach
   06:09 <~hatter> :(
   06:09 <@rorschach> there are a set of c constants that make up the ptrace requests
   06:10   >>> [email protected]
   06:10 <@rorschach> an extnesive list is in the man pages
   06:10 <@rorschach> however some of the main ones are
   06:10 <@rorschach> (sec)
   06:11 <@rorschach> ok
   06:11 <@rorschach> PTRACE_PTRACEME - set child to be traced
   06:11 <@rorschach> PTRACE_ATTACH - attach to pid
   06:11 <@rorschach> PTRACE_POKEDATA - put data in addr
   06:11 <@rorschach> PTRACE_PEEKDATA -read addr into data
   06:11 <@rorschach> PTRACE_GETREGS - get registers store in a user_regs struct
   06:11 <@rorschach> user_regs_struct*
   06:12 <@rorschach> for your notes: user_regs_struct is defined in user.h, it's not written in the man page..
   06:12 <@rorschach> afaik
   06:12 <@rorschach> PTRACE_SETREGS - set regs from a user_regs_struct
   06:12 <@rorschach> PTRACE_GETSIGINFO - get signal info, store in a siginfo_t struct
   06:13 <@rorschach> (this is in signal.h)
   06:13 <@rorschach> PTRACE_SETSIGINFO - set signal info from siginfo_t
   06:13 <@rorschach> PTRACE_CONT
   06:13 <@rorschach> continue pid
   06:13 <@rorschach> PTRACE_DETACH - detach from pid
   06:13 <@rorschach> PTRACE_SINGLESTEP - step execution forward
   06:14 <@rorschach> PTRACE_SETOPTIONS sets various options such as fork tracing and stop at exit, etc.
   06:14 <@rorschach> 06:11 <@rorschach> PTRACE_PTRACEME - set child to be traced
   06:14 <@rorschach> PTRACE_TRACEME*
   06:14 <@rorschach> sorry
   06:14 <@rorschach> ok, the pid argument is the pid of the tracee
   06:15 <@rorschach> addr is the address to be read / written from in requests that it's relevant, when it's not, set to NULL
   06:16 <@rorschach> data is the same, but it's a void pointer to the data to be used, otherwise set to NULL
   06:16 <@rorschach> so, to create a new process and set it to be traced
   06:16 <@rorschach> you would first fork
   06:16 <@rorschach> so
   06:16 <@rorschach> if(fork() == 0)
   06:16 <@rorschach> {
   06:17 <@rorschach>   ptrace(PTRACE_TRACEME, 0, NULL, NULL); /tell the parent to trace this child.
   06:18 <@rorschach>   execv(...); // execute traced process
   06:18 <@rorschach> }
   06:19 <@rorschach> TRACEME just sets the process to be traced
   06:19 <@rorschach> to attach to a process
   06:19 <@rorschach> just: ptrace(PTRACE_ATTACH, pid, NULL, NULL);
   06:20 <@rorschach> beyond this, attaching and creating processes is identical
   06:20 <@rorschach> err, the usage of ptrace
   06:20 <@rorschach> is identical
   06:20 <@rorschach> to get the register of a traced process
   06:21 <@rorschach> first create a regs struct to store it all
   06:21 <@rorschach> struct user_regs_struct regs;
   06:21 <@rorschach> ptrace(PTRACE_GETREGS, cpid, NULL, &regs);
   06:21 <@rorschach> printf("%x\n", regs.eip);
   06:22 <@rorschach> after calling GETREGS, the registers will be stored in a struct and can be accessed by regs.<register name>
   06:23 <@rorschach> The usage of SETREGS is identical, but should be preceded by a call to GETREGS to ensure that all register values are valid
   06:23 <@rorschach> (don't just create it give a value for eip then run SETREGS)
   06:24 <@rorschach> ie:
   06:24 <@rorschach> struct user_regs_struct regs;
   06:24 <@rorschach> ptrace(PTRACE_GETREGS, cpid, NULL, &regs);
   06:24 <@rorschach> regs.eip++;
   06:24 <@rorschach> ptrace(PTRACE_SETREGS, cpid, NULL, &regs);
   06:24 <@rorschach> is everyone following so far?
   06:24 <@rorschach> and am I moving to slow?
   06:25 <@rorschach> peekdata and pokedata function in much the same way
   06:26 <@rorschach> as do getsiginfo and setsiginfo
   06:26 <@rorschach> so I won't cover them
   06:27 <@rorschach> now, after creating or attaching to a process, a breakpoint will be hit and can be safely stepped over into a wait() function
   06:27 <@rorschach> wait() waits for a signal from the child
   06:27 <@rorschach> this way ptrace can act on the signal
   06:28 <@rorschach> this expects a reference to an integer that will contain the status of the process
   06:29 <@rorschach> so after wait() returns, you can find out if the child exited with
   06:29 <@rorschach> if(WIFEXITED(status))
   06:29 <@rorschach> after that, the signal number can be returned with
   06:29 <@rorschach> PTRACE_GETSIGINFO
   06:30 <@rorschach> ptrace(PTRACE_GETSIGINFO, cpid, NULL, sig);
   06:30 <@rorschach> assuming that a siginfo_t sig exists
   06:30 <@rorschach> sorry
   06:30 <@rorschach> ptrace(PTRACE_GETSIGINFO, cpid, NULL, &sig);
   06:33 <@rorschach> a list of valid signals can be found with
   06:33 <@rorschach> man 7 signal
   06:33 <@rorschach> everyone following?
   06:33 < alphis> yup
   06:35 <@rorschach> cool
   06:35 <@rorschach> ok, so that's the basic usage
   06:36 <@rorschach> a breakpoint can be set by reading from the location you want to set a breakpoint at
   06:36 <@rorschach> with peekdata
   06:36 <@rorschach> for example:
   06:36 <@rorschach>         ptrace(PTRACE_GETREGS, cpid, NULL, &regs);
   06:36 <@rorschach>         origdata = ptrace(PTRACE_PEEKDATA, cpid, (void*)regs.eip+5, NULL);
   06:37 <@rorschach> where origdata is a long
   06:37 <@rorschach> then the least significant byte is replaced with a 0xcc and then written back
   06:37 <@rorschach>         long data = (origdata & 0xffffff00) | 0xcc;
   06:37 <@rorschach>         ptrace(PTRACE_POKEDATA, cpid, (void*)regs.eip+5, (void*)data);
   06:37 <@rorschach> (0xcc is the trap instruction)
   06:38 <@rorschach> regs.eip+5 would be replaced with the address you want to set the breakpoint at
   06:39 <@rorschach> now, when the breakpoint is hit, it should be replaced with the original data and then EIP should be set back one instruction (to bypass the illegal instruction)
   06:39 Irssi: Pasting 7 lines to #CSIII. Press Ctrl-K if you wish to do this or Ctrl-C to cancel.
   06:39 <@rorschach>       else if(siginfo.si_signo == 5)
   06:39 <@rorschach>       {
   06:39 <@rorschach>         printf("Breakpoint hit, removing.\n");
   06:39 <@rorschach>         ptrace(PTRACE_GETREGS, cpid, NULL, &regs);
   06:39 <@rorschach>         ptrace(PTRACE_POKEDATA, cpid, (void*)regs.eip, (void*)origdata);
   06:39 <@rorschach>         regs.eip--;
   06:39 <@rorschach>         ptrace(PTRACE_SETREGS, cpid, NULL, &regs);
   06:39 <@rorschach>       }
   06:39 <@rorschach> follow?
   06:39 < alphis> yup
   06:40 <@rorschach> also, 5 is the signal number for sigtrap
   06:40 <@rorschach> issued when \x00 is hit
   06:40 <@rorschach> err
   06:40 <@rorschach> \xcc
   06:40 <@rorschach> derp
   06:40 <@rorschach> ok, so here's a large example of ptrace usage that has examples of everything covered
   06:41 <@rorschach> not large, but larger scope
   06:41 <@rorschach>
   06:41 <@rorschach> everyone take a look at that code andmake sure you understand everything going on in it before we move on
   06:42 <@rorschach> it's kind of a bad example I wrote up in half an hour
   06:42 <@rorschach> but it works
   06:42 < alphis> whats 11 and 6
   06:42 <@rorschach> SIGABRT and SIGSEGV
   06:43 < alphis> cool thx
   06:43 <@rorschach> yup
   06:43 <@rorschach> everything make sense guys?
   06:44 < alphis> yah
   06:44 <@rorschach> ok
   06:44 <@rorschach> ptrace can be used for all sorts of htings like being implemented in a fuzzer or a custom debugger
   06:44 <@rorschach> the sky is the limit
   06:45 <@rorschach> you could use it as a process injector
   06:45 < alphis> <-- <3 ptrace
   06:45 <@rorschach> sort of like what meterpreter does on windows for process migration
   06:45 <@rorschach> alphis: :D
   06:45 < alphis> would it be too tangential to talk about ptrace used for process injection
   06:45 <@rorschach> not really
   06:46 <@rorschach> I've never done it before though
   06:46 < alphis> ive had varied success with it. usually have to use wait()
   06:46 < alphis> oh ok. ur right tho it does work
   06:46 <@rorschach> but essentially, you would have to find free space in memory, write your code to it, then create a thread in the process and run your code
   06:46 <@rorschach> right?
   06:46 < Dwaan> sounds illegal
   06:46 < alphis> yeah
   06:47 < alphis> problems arise in practice tho
   06:47 <@rorschach> Dwaan: xD
   06:47 <@rorschach> yeah, probably
   06:47 < alphis> code to create thread needs to be PIC
   06:47 < alphis> position independant code to clarify
   06:47 <@rorschach> hmm
   06:47 <@rorschach> I'll play with it someday
   06:47 < alphis> you also need to halt program and set eip
   06:47 < alphis> then make it set back to where it was before after its done
   06:47 <@rorschach> yeah
   06:47 <@rorschach> that wouldn't be too difficult
   06:48 <@rorschach> and so fast it would liely not be noticable
   06:48 <@rorschach> likely*
   06:48 < alphis> certainly not noticable
   06:49 <@rorschach> also, with hatter's help, I wrote a ptrace wrapper in python, it's not complete but it allows ptrace to be used from python just like you would in C
   06:49 <@rorschach>
   06:50 <@rorschach> essentially, it imports the function from using python ctypes then reconstructs the various structs you would use
   06:50 <@rorschach> in case anybody wants to use it from python.
   06:50 <@rorschach> I think that concludes my presentation unless anyone has questions.
   06:51 <@rorschach> going once
   06:51 <@rorschach> going twice..
   06:51 <@rorschach> no? ok.
   06:51 <~hatter> er
   06:51   hatter sets +v zzzzzZZZZzzz
   06:51 <~hatter> there
   06:51 <@rorschach> sup
   06:52 <+zzzzzZZZZzzz> How abstracted is that python module?
   06:52 <+zzzzzZZZZzzz> none?
   06:52 <@rorschach> yeah
   06:52 <@rorschach> as little as I could
   06:52 <+zzzzzZZZZzzz> Fair.
   06:52 < alphis> rorschach: thanks for the presentation =]
   06:52 <@rorschach> there was a python-ptrace I had used that abstracted everything and it bugged the hell out of me
   06:52 <@rorschach> alphis: no problem :)
   06:52 <+zzzzzZZZZzzz> lol
   06:53 <@rorschach> zzzzzZZZZzzz:
   06:53 <@rorschach> usage is basically the same as in C
   06:54 <@rorschach> essentially, the only abstracting I did was to prevent the user from having to use ctypes directly
   06:54 <+zzzzzZZZZzzz> Right
   06:54 <+zzzzzZZZZzzz> Niceties without magic
   06:55 <@rorschach> yeah
   06:55 <@rorschach> nobody wants to have to learn another interface when tehy already know ptrace
   06:55 <@rorschach> that's why I got irritated with xisting ones, they wrapped everything and made it way high level
   06:55 <+zzzzzZZZZzzz> ^^